/interpreter/tags/at2-build060407/src/edu/vub/at/objects/symbiosis/JavaPackage.java
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 */ 28package edu.vub.at.objects.symbiosis; 29 30import edu.vub.at.exceptions.InterpreterException; 31import edu.vub.at.exceptions.XClassNotFound; 32import edu.vub.at.objects.ATContext; 33import edu.vub.at.objects.ATObject; 34import edu.vub.at.objects.ATStripe; 35import edu.vub.at.objects.ATTable; 36import edu.vub.at.objects.coercion.NativeStripes; 37import edu.vub.at.objects.grammar.ATSymbol; 38import edu.vub.at.objects.mirrors.PrimitiveMethod; 39import edu.vub.at.objects.mirrors.Reflection; 40import edu.vub.at.objects.natives.FieldMap; 41import edu.vub.at.objects.natives.MethodDictionary; 42import edu.vub.at.objects.natives.NATNumber; 43import edu.vub.at.objects.natives.NATObject; 44import edu.vub.at.objects.natives.NATTable; 45import edu.vub.at.objects.natives.NATText; 46import edu.vub.at.objects.natives.grammar.AGSymbol; 47 48import java.util.LinkedList; 49import java.util.Vector; 50 51/** 52 * A JavaPackage represents (part of) a Java package name and serves the same purpose 53 * as AmbientTalk Namespace objects, but for loading Java classes rather than AT objects. 54 * 55 * The behaviour of a JavaPackage object relies on Java naming conventions for automatic 56 * loading of classes. If some Java code does not follow the naming conventions, then explicit 57 * loading of packages or classes must be done via a JavaPackage's provided base-level methods. 58 * 59 * Selecting a field f from a JavaPackage encapsulating the path p has the following semantics: 60 * - if f starts with an uppercase symbol, the field access is interpreted as a class reference: 61 * The JavaPackage tries to load the class p.f. 62 * If the class does not exist, an XSelectorNotFound exception is thrown. 63 * - if f starts with a lowercase symbol, the field access is interpreted as a subpackage reference: 64 * The JavaPackage creates a new field referring to a JavaPackage whose path equals 'p.f.' 65 * 66 * JavaPackage instances are isolates, hence, they are pass-by-copy. 67 * 68 * @author tvcutsem 69 */ 70public final class JavaPackage extends NATObject { 71 72 private static final String _PKG_SEP_ = "."; 73 74 /** def class(name) { nil } */ 75 private static final PrimitiveMethod _PRIM_CLS_ = new PrimitiveMethod( 76 AGSymbol.jAlloc("class"), NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("name")})) { 77 public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException { 78 return ((JavaPackage)ctx.base_getLexicalScope()).base_class(arguments.base_at(NATNumber.ONE).asSymbol()); 79 } 80 }; 81 /** def package(name) { nil } */ 82 private static final PrimitiveMethod _PRIM_PKG_ = new PrimitiveMethod( 83 AGSymbol.jAlloc("package"), NATTable.atValue(new ATObject[] { AGSymbol.jAlloc("name")})) { 84 public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException { 85 return ((JavaPackage)ctx.base_getLexicalScope()).base_package(arguments.base_at(NATNumber.ONE).asSymbol()); 86 } 87 }; 88 89 private final String path_; 90 91 /** 92 * A JavaPackage object encapsulates a package path. 93 * A package path is a '.'-separated string, always ending with a '.' 94 * The jlobby root package has an empty package path 95 * 96 * A JavaPackage is initialized as an AT/2 isolate object. 97 * 98 * @param path the pathname of this JavaPackage, e.g. 'java.' or 'java.lang.' 99 */ 100 public JavaPackage(String path) { 101 super(new ATStripe[] { NativeStripes._ISOLATE_ }); 102 path_ = path; 103 try { 104 super.meta_addMethod(_PRIM_CLS_); 105 super.meta_addMethod(_PRIM_PKG_); 106 } catch (InterpreterException e) { 107 throw new RuntimeException("Failed to initialize a JavaPackage: " + e.getMessage()); 108 } 109 } 110 111 /** 112 * Private constructor used only for cloning 113 */ 114 private JavaPackage(FieldMap map, 115 Vector state, 116 LinkedList customFields, 117 MethodDictionary methodDict, 118 ATObject dynamicParent, 119 ATObject lexicalParent, 120 byte flags, 121 ATStripe[] stripes, 122 String path) throws InterpreterException { 123 super(map, state, customFields, methodDict, dynamicParent, lexicalParent, flags, stripes); 124 path_ = path; 125 } 126 127 /** 128 * For a JavaPackage object, doesNotUnderstand triggers the querying of the Java classpath 129 * to load classes corresponding to the missing selector. Depending on the case of the 130 * selector's first letter, the access is interpreted as a class or a package reference. 131 */ 132 public ATObject meta_doesNotUnderstand(ATSymbol selector) throws InterpreterException { 133 // first, convert the AmbientTalk name to a Java selector. 134 String s = selector.base_getText().asNativeText().javaValue; 135 if (Character.isUpperCase(s.charAt(0))) { 136 // the field access is interpreted as a class reference 137 return base_class(selector); 138 } else { 139 // the field access is interpreted as a package reference 140 return base_package(selector); 141 } 142 } 143 144 public NATText meta_print() throws InterpreterException { 145 return NATText.atValue("<jpackage:"+path_+">"); 146 } 147 148 protected NATObject createClone(FieldMap map, 149 Vector state, 150 LinkedList customFields, 151 MethodDictionary methodDict, 152 ATObject dynamicParent, 153 ATObject lexicalParent, 154 byte flags, ATStripe[] stripes) throws InterpreterException { 155 return new JavaPackage(map, 156 state, 157 customFields, 158 methodDict, 159 dynamicParent, 160 lexicalParent, 161 flags, 162 stripes, 163 path_); 164 } 165 166 /** 167 * Allows the AT programmer to explicitly load a class. This might be necessary if the 168 * class starts with a lowercase letter. 169 */ 170 public ATObject base_class(ATSymbol selector) throws InterpreterException { 171 // try to see if a class corresponding to the selector prefixed with 172 // this package's pathname exists 173 String qualifiedClassname = path_ + Reflection.upSelector(selector); 174 try { 175 Class c = Class.forName(qualifiedClassname); 176 JavaClass jc = JavaClass.wrapperFor(c); 177 // bind the new class to the selector within this JavaPackage 178 this.meta_defineField(selector, jc); 179 return jc; 180 } catch (ClassNotFoundException e) { 181 throw new XClassNotFound(qualifiedClassname, e); 182 } 183 } 184 185 /** 186 * Allows the AT programmer to explicitly load a package. This might be necessary if the 187 * package starts with an uppercase letter. 188 */ 189 public ATObject base_package(ATSymbol selector) throws InterpreterException { 190 // define a new Java package with a trailing '.' 191 JavaPackage jpkg = new JavaPackage(path_ + Reflection.upSelector(selector) + _PKG_SEP_); 192 this.meta_defineField(selector, jpkg); 193 return jpkg; 194 } 195 196}