/interpreter/tags/at2-build060407/src/edu/vub/at/objects/symbiosis/JavaPackage.java

http://ambienttalk.googlecode.com/ · Java · 196 lines · 102 code · 14 blank · 80 comment · 2 complexity · 7f02f9834733074fd228642f9c958f80 MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * JavaPackage.java created on 19-nov-2006 at 12:31:39
  4. * (c) Programming Technology Lab, 2006 - 2007
  5. * Authors: Tom Van Cutsem & Stijn Mostinckx
  6. *
  7. * Permission is hereby granted, free of charge, to any person
  8. * obtaining a copy of this software and associated documentation
  9. * files (the "Software"), to deal in the Software without
  10. * restriction, including without limitation the rights to use,
  11. * copy, modify, merge, publish, distribute, sublicense, and/or
  12. * sell copies of the Software, and to permit persons to whom the
  13. * Software is furnished to do so, subject to the following
  14. * conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be
  17. * included in all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  21. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  22. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  23. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  24. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  25. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  26. * OTHER DEALINGS IN THE SOFTWARE.
  27. */
  28. package edu.vub.at.objects.symbiosis;
  29. import edu.vub.at.exceptions.InterpreterException;
  30. import edu.vub.at.exceptions.XClassNotFound;
  31. import edu.vub.at.objects.ATContext;
  32. import edu.vub.at.objects.ATObject;
  33. import edu.vub.at.objects.ATStripe;
  34. import edu.vub.at.objects.ATTable;
  35. import edu.vub.at.objects.coercion.NativeStripes;
  36. import edu.vub.at.objects.grammar.ATSymbol;
  37. import edu.vub.at.objects.mirrors.PrimitiveMethod;
  38. import edu.vub.at.objects.mirrors.Reflection;
  39. import edu.vub.at.objects.natives.FieldMap;
  40. import edu.vub.at.objects.natives.MethodDictionary;
  41. import edu.vub.at.objects.natives.NATNumber;
  42. import edu.vub.at.objects.natives.NATObject;
  43. import edu.vub.at.objects.natives.NATTable;
  44. import edu.vub.at.objects.natives.NATText;
  45. import edu.vub.at.objects.natives.grammar.AGSymbol;
  46. import java.util.LinkedList;
  47. import java.util.Vector;
  48. /**
  49. * A JavaPackage represents (part of) a Java package name and serves the same purpose
  50. * as AmbientTalk Namespace objects, but for loading Java classes rather than AT objects.
  51. *
  52. * The behaviour of a JavaPackage object relies on Java naming conventions for automatic
  53. * loading of classes. If some Java code does not follow the naming conventions, then explicit
  54. * loading of packages or classes must be done via a JavaPackage's provided base-level methods.
  55. *
  56. * Selecting a field f from a JavaPackage encapsulating the path p has the following semantics:
  57. * - if f starts with an uppercase symbol, the field access is interpreted as a class reference:
  58. * The JavaPackage tries to load the class p.f.
  59. * If the class does not exist, an XSelectorNotFound exception is thrown.
  60. * - if f starts with a lowercase symbol, the field access is interpreted as a subpackage reference:
  61. * The JavaPackage creates a new field referring to a JavaPackage whose path equals 'p.f.'
  62. *
  63. * JavaPackage instances are isolates, hence, they are pass-by-copy.
  64. *
  65. * @author tvcutsem
  66. */
  67. public final class JavaPackage extends NATObject {
  68. private static final String _PKG_SEP_ = ".";
  69. /** def class(name) { nil } */
  70. private static final PrimitiveMethod _PRIM_CLS_ = new PrimitiveMethod(
  71. AGSymbol.jAlloc("class"), NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("name")})) {
  72. public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
  73. return ((JavaPackage)ctx.base_getLexicalScope()).base_class(arguments.base_at(NATNumber.ONE).asSymbol());
  74. }
  75. };
  76. /** def package(name) { nil } */
  77. private static final PrimitiveMethod _PRIM_PKG_ = new PrimitiveMethod(
  78. AGSymbol.jAlloc("package"), NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("name")})) {
  79. public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
  80. return ((JavaPackage)ctx.base_getLexicalScope()).base_package(arguments.base_at(NATNumber.ONE).asSymbol());
  81. }
  82. };
  83. private final String path_;
  84. /**
  85. * A JavaPackage object encapsulates a package path.
  86. * A package path is a '.'-separated string, always ending with a '.'
  87. * The jlobby root package has an empty package path
  88. *
  89. * A JavaPackage is initialized as an AT/2 isolate object.
  90. *
  91. * @param path the pathname of this JavaPackage, e.g. 'java.' or 'java.lang.'
  92. */
  93. public JavaPackage(String path) {
  94. super(new ATStripe[] { NativeStripes._ISOLATE_ });
  95. path_ = path;
  96. try {
  97. super.meta_addMethod(_PRIM_CLS_);
  98. super.meta_addMethod(_PRIM_PKG_);
  99. } catch (InterpreterException e) {
  100. throw new RuntimeException("Failed to initialize a JavaPackage: " + e.getMessage());
  101. }
  102. }
  103. /**
  104. * Private constructor used only for cloning
  105. */
  106. private JavaPackage(FieldMap map,
  107. Vector state,
  108. LinkedList customFields,
  109. MethodDictionary methodDict,
  110. ATObject dynamicParent,
  111. ATObject lexicalParent,
  112. byte flags,
  113. ATStripe[] stripes,
  114. String path) throws InterpreterException {
  115. super(map, state, customFields, methodDict, dynamicParent, lexicalParent, flags, stripes);
  116. path_ = path;
  117. }
  118. /**
  119. * For a JavaPackage object, doesNotUnderstand triggers the querying of the Java classpath
  120. * to load classes corresponding to the missing selector. Depending on the case of the
  121. * selector's first letter, the access is interpreted as a class or a package reference.
  122. */
  123. public ATObject meta_doesNotUnderstand(ATSymbol selector) throws InterpreterException {
  124. // first, convert the AmbientTalk name to a Java selector.
  125. String s = selector.base_getText().asNativeText().javaValue;
  126. if (Character.isUpperCase(s.charAt(0))) {
  127. // the field access is interpreted as a class reference
  128. return base_class(selector);
  129. } else {
  130. // the field access is interpreted as a package reference
  131. return base_package(selector);
  132. }
  133. }
  134. public NATText meta_print() throws InterpreterException {
  135. return NATText.atValue("<jpackage:"+path_+">");
  136. }
  137. protected NATObject createClone(FieldMap map,
  138. Vector state,
  139. LinkedList customFields,
  140. MethodDictionary methodDict,
  141. ATObject dynamicParent,
  142. ATObject lexicalParent,
  143. byte flags, ATStripe[] stripes) throws InterpreterException {
  144. return new JavaPackage(map,
  145. state,
  146. customFields,
  147. methodDict,
  148. dynamicParent,
  149. lexicalParent,
  150. flags,
  151. stripes,
  152. path_);
  153. }
  154. /**
  155. * Allows the AT programmer to explicitly load a class. This might be necessary if the
  156. * class starts with a lowercase letter.
  157. */
  158. public ATObject base_class(ATSymbol selector) throws InterpreterException {
  159. // try to see if a class corresponding to the selector prefixed with
  160. // this package's pathname exists
  161. String qualifiedClassname = path_ + Reflection.upSelector(selector);
  162. try {
  163. Class c = Class.forName(qualifiedClassname);
  164. JavaClass jc = JavaClass.wrapperFor(c);
  165. // bind the new class to the selector within this JavaPackage
  166. this.meta_defineField(selector, jc);
  167. return jc;
  168. } catch (ClassNotFoundException e) {
  169. throw new XClassNotFound(qualifiedClassname, e);
  170. }
  171. }
  172. /**
  173. * Allows the AT programmer to explicitly load a package. This might be necessary if the
  174. * package starts with an uppercase letter.
  175. */
  176. public ATObject base_package(ATSymbol selector) throws InterpreterException {
  177. // define a new Java package with a trailing '.'
  178. JavaPackage jpkg = new JavaPackage(path_ + Reflection.upSelector(selector) + _PKG_SEP_);
  179. this.meta_defineField(selector, jpkg);
  180. return jpkg;
  181. }
  182. }