PageRenderTime 64ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sys/java/fan/sys/Pod.java

https://bitbucket.org/bedlaczech/fan-1.0
Java | 536 lines | 378 code | 68 blank | 90 comment | 87 complexity | a50119d653d5a4d0bf9b8ca40ae26c4a MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2006, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 2 Dec 05 Brian Frank Creation
  7. //
  8. package fan.sys;
  9. import java.lang.ref.*;
  10. import java.io.File;
  11. import java.util.HashMap;
  12. import java.util.Iterator;
  13. import java.util.zip.*;
  14. import fanx.fcode.*;
  15. import fanx.emit.*;
  16. import fanx.util.*;
  17. /**
  18. * Pod is a module containing Types. A Pod is always backed by a FPod
  19. * instance which defines all the definition tables. Usually the FPod
  20. * is in turn backed by a FStore for the pod's zip file. However in the
  21. * case of memory-only pods defined by the compiler, the fpod.store field
  22. * will be null.
  23. *
  24. * Pods is loaded as soon as it is constructed:
  25. * 1) All the types defined by the fpod are mapped into hollow Types.
  26. * 2) It is emitted as a Java class called "fan.{podName}.$Pod". The
  27. * emitted class is basically a manifestation of the literal tables,
  28. * after which we can clear the fpod data structures.
  29. */
  30. public class Pod
  31. extends FanObj
  32. {
  33. //////////////////////////////////////////////////////////////////////////
  34. // Management
  35. //////////////////////////////////////////////////////////////////////////
  36. public static Pod of(Object obj)
  37. {
  38. return Type.of(obj).pod();
  39. }
  40. public static Pod find(String name) { return doFind(name, true, null, null); }
  41. public static Pod find(String name, boolean checked) { return doFind(name, checked, null, null); }
  42. public static Pod doFind(String name, boolean checked, FPod fpod, HashMap resolving)
  43. {
  44. try
  45. {
  46. synchronized(podsByName)
  47. {
  48. SoftReference ref = (SoftReference)podsByName.get(name);
  49. if (ref == null || ref.get() == null)
  50. {
  51. // if resolving is non-null, check that our pod name it
  52. // isn't in the resolving map, because then we have a cyclic
  53. // dependency which is bad, bad, bad
  54. if (resolving == null) resolving = new HashMap();
  55. if (resolving != null && resolving.containsKey(name))
  56. throw new Exception("Cyclic dependency on '" + name + "'");
  57. resolving.put(name, name);
  58. // if fpod is non-null, then we are "creating" this pod in
  59. // memory direct from the compiler, otherwise we need to
  60. // find the pod zip file and load it's meta-data
  61. if (fpod == null) fpod = readFPod(name);
  62. // sanity check
  63. if (!fpod.podName.equals(name))
  64. throw new Exception("Mismatched pod name b/w pod.def and pod zip filename: " + fpod.podName + " != " + name);
  65. // dependency check, keep track of what we are loading
  66. // via depends checking to prevent a cyclic dependency
  67. // from putting us into an infinite loop
  68. Pod[] dependPods = new Pod[fpod.depends.length];
  69. for (int i=0; i<fpod.depends.length; ++i)
  70. {
  71. Depend d = fpod.depends[i];
  72. Pod dpod = doFind(d.name(), false, null, resolving);
  73. if (dpod == null)
  74. throw new Exception("Missing dependency for '" + name + "': " + d);
  75. if (!d.match(dpod.version()))
  76. throw new Exception("Missing dependency for '" + name + "': " + dpod.name() + " " + dpod.version() + " != " + d);
  77. dependPods[i] = dpod;
  78. }
  79. // create the pod and register it
  80. ref = new SoftReference(new Pod(fpod, dependPods));
  81. podsByName.put(name, ref);
  82. }
  83. return (Pod)ref.get();
  84. }
  85. }
  86. catch (UnknownPodErr e)
  87. {
  88. if (!checked) return null;
  89. throw e;
  90. }
  91. catch (Exception e)
  92. {
  93. e.printStackTrace();
  94. if (!checked) return null;
  95. throw UnknownPodErr.make(name, Err.make(e));
  96. }
  97. }
  98. public static Pod load(InStream in)
  99. {
  100. FPod fpod = null;
  101. try
  102. {
  103. fpod = new FPod(null, null);
  104. fpod.readFully(new ZipInputStream(SysInStream.java(in)));
  105. }
  106. catch (Exception e)
  107. {
  108. throw Err.make(e);
  109. }
  110. String name = fpod.podName;
  111. synchronized(podsByName)
  112. {
  113. // check for duplicate pod name
  114. SoftReference ref = (SoftReference)podsByName.get(name);
  115. if (ref != null && ref.get() != null)
  116. throw Err.make("Duplicate pod name: " + name);
  117. // create Pod and add to master table
  118. Pod pod = new Pod(fpod, new Pod[]{});
  119. podsByName.put(name, new SoftReference(pod));
  120. return pod;
  121. }
  122. }
  123. public static FPod readFPod(String name)
  124. throws Exception
  125. {
  126. FStore store = null;
  127. // otherwise if we are running with JarDistEnv use my own classloader
  128. if (Sys.isJarDist)
  129. {
  130. store = FStore.makeJarDist(Pod.class.getClassLoader(), name);
  131. }
  132. // handle sys specially for bootstrapping the VM
  133. else if (name.equals("sys"))
  134. {
  135. store = FStore.makeZip(new File(Sys.podsDir, name + ".pod"));
  136. }
  137. // otherwise delete to Env.cur to find the pod file
  138. else
  139. {
  140. File file = null;
  141. fan.sys.File f = Env.cur().findPodFile(name);
  142. if (f != null) file = ((LocalFile)f).file;
  143. // if null or doesn't exist then its a no go
  144. if (file == null || !file.exists()) throw UnknownPodErr.make(name);
  145. // verify case since Windoze is case insensitive
  146. String actualName = file.getCanonicalFile().getName();
  147. actualName = actualName.substring(0, actualName.length()-4);
  148. if (!actualName.equals(name)) throw UnknownPodErr.make("Mismatch case: " + name + " != " + actualName);
  149. store = FStore.makeZip(file);
  150. }
  151. // read in the FPod tables
  152. FPod fpod = new FPod(name, store);
  153. fpod.read();
  154. return fpod;
  155. }
  156. public static List list()
  157. {
  158. synchronized(podsByName)
  159. {
  160. // eventually we need a faster way to load
  161. // pod meta-data into memory without actually loading
  162. // every pod into memory
  163. if (allPodsList == null)
  164. {
  165. List names = Env.cur().findAllPodNames();
  166. List pods = new List(Sys.PodType, names.sz());
  167. for (int i=0; i<names.sz(); ++i)
  168. {
  169. String name = (String)names.get(i);
  170. try
  171. {
  172. pods.add(doFind(name, true, null, null));
  173. }
  174. catch (Throwable e)
  175. {
  176. System.out.println("ERROR: Invalid pod file: " + name);
  177. e.printStackTrace();
  178. }
  179. }
  180. allPodsList = (List)pods.sort().toImmutable();
  181. }
  182. return allPodsList;
  183. }
  184. }
  185. //////////////////////////////////////////////////////////////////////////
  186. // Constructor
  187. //////////////////////////////////////////////////////////////////////////
  188. Pod(FPod fpod, Pod[] dependPods)
  189. {
  190. this.name = fpod.podName;
  191. this.classLoader = new FanClassLoader(this);
  192. this.dependPods = dependPods;
  193. load(fpod);
  194. }
  195. //////////////////////////////////////////////////////////////////////////
  196. // Methods
  197. //////////////////////////////////////////////////////////////////////////
  198. public Type typeof() { return Sys.PodType; }
  199. public final String name() { return name; }
  200. public final Version version()
  201. {
  202. if (version == null)
  203. version = Version.fromStr(fpod.podVersion);
  204. return version;
  205. }
  206. public final List depends()
  207. {
  208. if (depends == null)
  209. depends = (List)new List(Sys.DependType, fpod.depends).toImmutable();
  210. return depends;
  211. }
  212. public final Uri uri()
  213. {
  214. if (uri == null) uri = Uri.fromStr("fan://" + name);
  215. return uri;
  216. }
  217. public final String toStr() { return name; }
  218. public final Map meta()
  219. {
  220. if (meta == null)
  221. {
  222. try
  223. {
  224. if (fpod.meta != null) meta = (Map)fpod.meta;
  225. else
  226. {
  227. InStream in = new SysInStream(fpod.store.read("meta.props"));
  228. meta = (Map)in.readProps().toImmutable();
  229. in.close();
  230. }
  231. }
  232. catch (Exception e)
  233. {
  234. e.printStackTrace();
  235. meta = Sys.emptyStrStrMap;
  236. }
  237. }
  238. return meta;
  239. }
  240. //////////////////////////////////////////////////////////////////////////
  241. // Types
  242. //////////////////////////////////////////////////////////////////////////
  243. public List types() { return new List(Sys.TypeType, types); }
  244. public Type type(String name) { return type(name, true); }
  245. public Type type(String name, boolean checked)
  246. {
  247. Type type = (Type)typesByName.get(name);
  248. if (type != null) return type;
  249. if (checked) throw UnknownTypeErr.make(this.name + "::" + name);
  250. return null;
  251. }
  252. //////////////////////////////////////////////////////////////////////////
  253. // Documentation
  254. //////////////////////////////////////////////////////////////////////////
  255. public String doc()
  256. {
  257. if (!docLoaded)
  258. {
  259. try
  260. {
  261. java.io.InputStream in = fpod.store.read("doc/pod.fandoc");
  262. if (in != null) doc = SysInStream.make(in, Long.valueOf(1024L)).readAllStr();
  263. }
  264. catch (Exception e) { e.printStackTrace(); }
  265. docLoaded = true;
  266. }
  267. return doc;
  268. }
  269. //////////////////////////////////////////////////////////////////////////
  270. // Files
  271. //////////////////////////////////////////////////////////////////////////
  272. public final List files()
  273. {
  274. loadFiles();
  275. return filesList;
  276. }
  277. public final fan.sys.File file(Uri uri) { return file(uri, true); }
  278. public final fan.sys.File file(Uri uri, boolean checked)
  279. {
  280. loadFiles();
  281. if (!uri.isPathAbs())
  282. throw ArgErr.make("Pod.files Uri must be path abs: " + uri);
  283. if (uri.auth() != null && !uri.toStr().startsWith(uri().toStr()))
  284. throw ArgErr.make("Invalid base uri `" + uri + "` for `" + uri() + "`");
  285. else
  286. uri = this.uri().plus(uri);
  287. fan.sys.File f = (fan.sys.File)filesMap.get(uri);
  288. if (f != null || !checked) return f;
  289. throw UnresolvedErr.make(uri.toStr());
  290. }
  291. private void loadFiles()
  292. {
  293. synchronized (filesMap)
  294. {
  295. if (filesList != null) return;
  296. if (fpod.store == null) throw Err.make("Not backed by pod file: " + name);
  297. List list;
  298. try
  299. {
  300. this.filesList = (List)fpod.store.podFiles(uri()).toImmutable();
  301. }
  302. catch (java.io.IOException e)
  303. {
  304. e.printStackTrace();
  305. throw Err.make(e);
  306. }
  307. for (int i=0; i<filesList.sz(); ++i)
  308. {
  309. fan.sys.File f = (fan.sys.File)filesList.get(i);
  310. filesMap.put(f.uri(), f);
  311. }
  312. }
  313. }
  314. //////////////////////////////////////////////////////////////////////////
  315. // Utils
  316. //////////////////////////////////////////////////////////////////////////
  317. public final Log log()
  318. {
  319. if (log == null) log = Log.get(name);
  320. return log;
  321. }
  322. public final Map props(Uri uri, Duration maxAge)
  323. {
  324. return Env.cur().props(this, uri, maxAge);
  325. }
  326. public final String config(String key)
  327. {
  328. return Env.cur().config(this, key);
  329. }
  330. public final String config(String key, String def)
  331. {
  332. return Env.cur().config(this, key, def);
  333. }
  334. public final String locale(String key)
  335. {
  336. return Env.cur().locale(this, key);
  337. }
  338. public final String locale(String key, String def)
  339. {
  340. return Env.cur().locale(this, key, def);
  341. }
  342. //////////////////////////////////////////////////////////////////////////
  343. // Load
  344. //////////////////////////////////////////////////////////////////////////
  345. void load(FPod fpod)
  346. {
  347. this.fpod = fpod;
  348. this.typesByName = new HashMap();
  349. // create a hollow Type for each FType (this requires two steps,
  350. // because we don't necessary have all the Types created for
  351. // superclasses until this loop completes)
  352. types = new ClassType[fpod.types.length];
  353. for (int i=0; i<fpod.types.length; ++i)
  354. {
  355. // create type instance
  356. ClassType type = new ClassType(this, fpod.types[i]);
  357. // add to my data structures
  358. types[i] = type;
  359. if (typesByName.put(type.name, type) != null)
  360. throw Err.make("Invalid pod: " + name + " type already defined: " + type.name);
  361. }
  362. // get TypeType to use for mixin List (we need to handle case
  363. // when loading sys itself - and lookup within my own pod)
  364. Type typeType = Sys.TypeType;
  365. if (typeType == null)
  366. typeType = (Type)typesByName.get("Type");
  367. // now that everthing is mapped, we can fill in the super
  368. // class fields (unless something is wacked, this will only
  369. // use Types in my pod or in pods already loaded)
  370. for (int i=0; i<fpod.types.length; ++i)
  371. {
  372. FType ftype = fpod.types[i];
  373. ClassType type = types[i];
  374. type.base = type(ftype.base);
  375. Object[] mixins = new Object[ftype.mixins.length];
  376. for (int j=0; j<mixins.length; ++j)
  377. mixins[j] = type(ftype.mixins[j]);
  378. type.mixins = new List(typeType, mixins).ro();
  379. }
  380. }
  381. synchronized Class emit()
  382. {
  383. if (cls == null)
  384. {
  385. try
  386. {
  387. cls = Env.cur().loadPodClass(this);
  388. FPodEmit.initFields(this, fpod, cls);
  389. }
  390. catch (Exception e)
  391. {
  392. e.printStackTrace();
  393. throw new RuntimeException(e.toString());
  394. }
  395. }
  396. return cls;
  397. }
  398. synchronized void precompiled(Class cls)
  399. throws Exception
  400. {
  401. this.cls = cls;
  402. FPodEmit.initFields(this, fpod, cls);
  403. }
  404. Type type(int qname)
  405. {
  406. if (qname == 0xFFFF || qname == -1) return null;
  407. // lookup type with typeRef index
  408. FTypeRef ref = fpod.typeRef(qname);
  409. // if generic instance, then this type must be used in a method
  410. // signature, not type meta-data (b/c I can't subclass generic types),
  411. // so it's safe that my pod has been loaded and is now registered (in
  412. // case the generic type is parameterized via types in my pod)
  413. if (ref.isGenericInstance())
  414. return TypeParser.load(ref.signature, true, this);
  415. // if the pod name starts with "[java]" this is a direct FFI java type
  416. String podName = ref.podName;
  417. String typeName = ref.typeName;
  418. if (podName.startsWith("[java]"))
  419. {
  420. Type t = Env.cur().loadJavaType(this, podName, typeName);
  421. if (ref.isNullable()) t = t.toNullable();
  422. return t;
  423. }
  424. // otherwise I need to handle if I am loading my own pod, because
  425. // I might not yet be added to the system namespace if I'm just
  426. // loading my own hollow types
  427. Pod pod = podName.equals(name) ? this : Pod.doFind(podName, true, null, null);
  428. Type type = pod.type(typeName, false);
  429. if (type != null)
  430. {
  431. if (ref.isNullable()) type = type.toNullable();
  432. return type;
  433. }
  434. // handle generic parameter types (for sys pod only)
  435. if (this.name.equals("sys"))
  436. {
  437. type = Sys.genericParamType(typeName);
  438. if (type != null)
  439. {
  440. if (ref.isNullable()) type = type.toNullable();
  441. return type;
  442. }
  443. }
  444. // lost cause
  445. throw UnknownTypeErr.make(podName + "::" + typeName);
  446. }
  447. //////////////////////////////////////////////////////////////////////////
  448. // Fields
  449. //////////////////////////////////////////////////////////////////////////
  450. static HashMap podsByName = new HashMap();
  451. static List allPodsList = null;
  452. final String name;
  453. final FanClassLoader classLoader;
  454. final Pod[] dependPods;
  455. Uri uri;
  456. FPod fpod;
  457. Version version;
  458. Map meta;
  459. List depends;
  460. ClassType[] types;
  461. HashMap typesByName;
  462. Class cls;
  463. List filesList;
  464. HashMap filesMap = new HashMap(11);
  465. Log log;
  466. boolean docLoaded;
  467. public String doc;
  468. }