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