001: package sisc.interpreter;
002:
003: import java.io.*;
004: import java.net.URL;
005:
006: import sisc.ser.*;
007: import sisc.data.*;
008:
009: import java.security.AccessControlException;
010: import java.util.Properties;
011: import sisc.env.SymbolicEnvironment;
012: import sisc.util.Util;
013:
014: /**
015: * The AppContext is the root of all data in an instance
016: * of SISC. This encapsulates mainly the procedures and data
017: * which are defined in the global environment. It is also
018: * <i>the</i> token used by most Java to Scheme operations.
019: * <p>
020: * Typically, an AppContext is created using the default constructor,
021: * then initialized with a heap using utility methods in {@link sisc.REPL}.
022: *
023: **/
024: public class AppContext extends Util {
025:
026: public SymbolicEnvironment symenv;
027: public SymbolicEnvironment toplevel_env;
028:
029: private LibraryManager libraries;
030: private Properties props;
031:
032: /**
033: * Create a new, AppContext with default values,
034: * the recommended constructor for normal usage.
035: *
036: */
037: public AppContext() {
038: this (new Properties());
039: }
040:
041: /**
042: * Create a new AppContext, providing a set of properties explicitly.
043: *
044: * @param props Properties which govern the
045: * underlying Scheme environment.
046: */
047: public AppContext(Properties props) {
048: this .props = props;
049: libraries = new LibraryManager(this );
050: }
051:
052: /**
053: * Create a new AppContext, providing a custom global environment.
054: *
055: * @param symenv the global environment
056: */
057: public AppContext(SymbolicEnvironment symenv) {
058: this ();
059: this .symenv = symenv;
060: try {
061: toplevel_env = lookupContextEnv(TOPLEVEL);
062: } catch (ArrayIndexOutOfBoundsException ue) {
063: toplevel_env = symenv;
064: symenv.define(TOPLEVEL, toplevel_env.asValue());
065: }
066: }
067:
068: public Expression getExpression(Symbol name) {
069: try {
070: return libraries.getExpression(name);
071: } catch (java.io.IOException e) {
072: return null;
073: }
074: }
075:
076: // Heapfile loading/saving
077: public void loadEnv(SeekableDataInputStream i) throws IOException,
078: ClassNotFoundException {
079:
080: Library s = Library.load(this , i);
081:
082: libraries.addLibrary(s);
083:
084: SymbolicEnvironment lsymenv = (SymbolicEnvironment) s
085: .getExpression(SYMENV);
086: try {
087: symenv = lsymenv;
088: try {
089: toplevel_env = lookupContextEnv(TOPLEVEL);
090: } catch (ArrayIndexOutOfBoundsException e) {
091: e.printStackTrace();
092: throw new IOException(
093: "Heap did not contain toplevel environment!");
094: }
095: } catch (Exception e) {
096: e.printStackTrace();
097: throw new IOException(e.getMessage());
098: }
099: }
100:
101: public void saveEnv(OutputStream o, LibraryBuilder lb)
102: throws IOException {
103: lb.add(SYMENV, symenv.asValue());
104: lb.add(TOPLEVEL, toplevel_env.asValue());
105:
106: lb.buildLibrary("sisc", o);
107: }
108:
109: public SymbolicEnvironment lookupContextEnv(Symbol s) {
110: SymbolicEnvironment senv = (SymbolicEnvironment) symenv
111: .lookup(s);
112: if (senv == null)
113: throw new ArrayIndexOutOfBoundsException();
114: return senv;
115: }
116:
117: public void defineContextEnv(Symbol s, SymbolicEnvironment env) {
118: symenv.define(s, env.asValue());
119: }
120:
121: public String getProperty(String name) {
122: String res = props.getProperty(name);
123: if (res != null)
124: return res;
125: try {
126: res = System.getProperty(name);
127: } catch (SecurityException e) {
128: }
129: return res;
130: }
131:
132: public String getProperty(String name, String def) {
133: String res = getProperty(name);
134: return (res == null) ? def : res;
135: }
136:
137: public Expression resolveBinding(LibraryBinding lb)
138: throws IOException {
139: return libraries.resolveBinding(lb);
140: }
141:
142: public LibraryBinding lookupBinding(Expression e)
143: throws IOException {
144: return libraries.lookupBinding(e);
145: }
146:
147: /**
148: * Given a SeekableInputStream which
149: * is attached to a SISC heap file, loads the heap into this
150: * AppContext and initializes it. Returns true on success,
151: * false otherwise.
152: */
153: public boolean addHeap(SeekableInputStream in)
154: throws ClassNotFoundException {
155:
156: try {
157: loadEnv(new SeekableDataInputStream(in));
158: } catch (IOException e) {
159: System.err.println("\n"
160: + Util.liMessage(Util.SISCB, "errorloadingheap"));
161: e.printStackTrace();
162: return false;
163: }
164:
165: Interpreter r = Context.enter(this );
166: try {
167: try {
168: File[] roots = File.listRoots();
169: SchemeString[] rootss = new SchemeString[roots.length];
170: for (int i = 0; i < roots.length; i++)
171: rootss[i] = new SchemeString(roots[i].getPath());
172: r.define(Symbol.get("fs-roots"), Util.valArrayToList(
173: rootss, 0, rootss.length), Util.SISC);
174: } catch (java.security.AccessControlException ace) {
175: }
176:
177: try {
178: r.eval("(initialize)");
179: } catch (SchemeException se) {
180: System.err.println(Util.liMessage(Util.SISCB,
181: "errorduringinitialize")
182: + Util.simpleErrorToString((Pair) se.m));
183: } catch (IOException e) {
184: System.err.println(Util.liMessage(Util.SISCB,
185: "errorduringinitialize")
186: + e.getMessage());
187: }
188: } finally {
189: Context.exit();
190: }
191: return true;
192: }
193:
194: /**
195: * Attempts to find and load the default SISC heap into this
196: * AppContext.
197: *
198: * @see #findHeap(URL)
199: */
200: public void addDefaultHeap() throws IOException {
201: URL u = findHeap(null);
202: if (u == null) {
203: throw new RuntimeException(Util.liMessage(Util.SISCB,
204: "errorloadingheap"));
205: }
206: try {
207: if (!addHeap(openHeap(u)))
208: throw new RuntimeException(Util.liMessage(Util.SISCB,
209: "errorloadingheap"));
210: } catch (ClassNotFoundException e) {
211: throw new RuntimeException(Util.liMessage(Util.SISCB,
212: "errorloadingheap"));
213: }
214: }
215:
216: public static SeekableInputStream openHeap(URL u)
217: throws IOException {
218: //Handle files separately, as they can be efficiently used
219: //on disk in random access fashion.
220: if (u.getProtocol().equals("file")) {
221: try {
222: return new BufferedRandomAccessInputStream(new File(u
223: .getPath()), "r", 1, 8192);
224: } catch (AccessControlException ace) {
225: //Must be an applet, we'll have to load it as a URL stream
226: }
227: }
228: return new MemoryRandomAccessInputStream(u.openStream());
229: }
230:
231: /**
232: * Locate a heap.
233: *
234: * If the heap cannot be located at the supplied location then an
235: * attempt is made to find it as a resource <tt>"sisc.shp"</tt>.
236: *
237: * @param heapLocation The URL for the heap file. When
238: * this is <tt>null</tt> it defaults to the value of the
239: * <tt>sisc.heap</tt> system property and, if that is not present,
240: * <tt>"sisc.shp"</tt>
241: */
242: public static URL findHeap(URL heapLocation) {
243: if (heapLocation == null) {
244: try {
245: heapLocation = Util.makeURL(System
246: .getProperty("sisc.heap"));
247: } catch (SecurityException se) {
248: }
249: if (heapLocation == null) {
250: heapLocation = Util.makeURL("sisc.shp");
251: }
252: }
253: if (mightExist(heapLocation))
254: return heapLocation;
255: Class anchor = null;
256: try {
257: anchor = Class.forName("sisc.boot.HeapAnchor");
258: } catch (ClassNotFoundException cnf) {
259: }
260: if (anchor == null)
261: anchor = AppContext.class;
262: heapLocation = anchor.getResource("/sisc/boot/sisc.shp");
263: if (mightExist(heapLocation))
264: return heapLocation;
265: return null;
266: }
267:
268: private static boolean mightExist(URL u) {
269: if (u == null)
270: return false;
271: if (u.getProtocol().equals("file")) {
272: try {
273: return new File(u.getPath()).exists();
274: } catch (AccessControlException ace) {
275: // Running as an applet. need to actually open the file to try this out:
276: try {
277: u.openStream().close();
278: return true;
279: } catch (Exception e) {
280: //Oops, guess not
281: return false;
282: }
283:
284: }
285: } else
286: return true;
287: }
288: }
289:
290: /*
291: * The contents of this file are subject to the Mozilla Public
292: * License Version 1.1 (the "License"); you may not use this file
293: * except in compliance with the License. You may obtain a copy of
294: * the License at http://www.mozilla.org/MPL/
295: *
296: * Software distributed under the License is distributed on an "AS
297: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
298: * implied. See the License for the specific language governing
299: * rights and limitations under the License.
300: *
301: * The Original Code is the Second Interpreter of Scheme Code (SISC).
302: *
303: * The Initial Developer of the Original Code is Scott G. Miller.
304: * Portions created by Scott G. Miller are Copyright (C) 2000-2007
305: * Scott G. Miller. All Rights Reserved.
306: *
307: * Contributor(s):
308: * Matthias Radestock
309: *
310: * Alternatively, the contents of this file may be used under the
311: * terms of the GNU General Public License Version 2 or later (the
312: * "GPL"), in which case the provisions of the GPL are applicable
313: * instead of those above. If you wish to allow use of your
314: * version of this file only under the terms of the GPL and not to
315: * allow others to use your version of this file under the MPL,
316: * indicate your decision by deleting the provisions above and
317: * replace them with the notice and other provisions required by
318: * the GPL. If you do not delete the provisions above, a recipient
319: * may use your version of this file under either the MPL or the
320: * GPL.
321: */
|