001: /*
002: (c) Copyright 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: All rights reserved - see end of file.
004: $Id: AssemblerHelp.java,v 1.22 2008/01/24 16:00:14 chris-dollin Exp $
005: */
006:
007: package com.hp.hpl.jena.assembler;
008:
009: import java.lang.reflect.*;
010: import java.util.*;
011:
012: import com.hp.hpl.jena.assembler.assemblers.AssemblerGroup;
013: import com.hp.hpl.jena.assembler.exceptions.*;
014: import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
015: import com.hp.hpl.jena.rdf.model.*;
016: import com.hp.hpl.jena.shared.*;
017: import com.hp.hpl.jena.vocabulary.*;
018:
019: /**
020: AssemblerHelp provides utility methods used by, and useful for working with,
021: the Assembler code, including the methods that expand a model to include the
022: required inferences and to find the most specific type of a root in an
023: assembler specification.
024:
025: @author kers
026: */
027: public class AssemblerHelp {
028: /**
029: A useful constant for <code>listStatements(S, P, O)</code>.
030: */
031: protected static Property ANY = null;
032:
033: /**
034: Answer a Resource .equals() to <code>root</code>, but in the expanded
035: model.
036: */
037: public static Resource withFullModel(Resource root) {
038: return (Resource) root.inModel(fullModel(root.getModel()));
039: }
040:
041: /**
042: Answer the full model of <code>m</code>, with all its imports included and
043: with the necessary properties added from the JA schema. However, if
044: the magic footprint triple (ja:this, rdf:type, ja:Expanded) is present in the
045: model, it is returned unchanged. Imports are managed by the shared
046: <code>ImportManager.instance</code>.
047: */
048: public static Model fullModel(Model m) {
049: return fullModel(ImportManager.instance, m);
050: }
051:
052: /**
053: Answer the full model of <code>m</code>, with all its imports included and
054: with the necessary properties added from the JA schema. However, if
055: the magic footprint triple (ja:this, rdf:type, ja:Expanded) is present in the
056: model, it is returned unchanged. Imports are managed by <code>im</code>.
057: */
058: public static Model fullModel(ImportManager im, Model m) {
059: return m.contains(JA.This, RDF.type, JA.Expanded) ? m
060: : (Model) ModelExpansion.withSchema(im.withImports(m),
061: JA.getSchema()).add(JA.This, RDF.type,
062: JA.Expanded).setNsPrefixes(
063: PrefixMapping.Extended).setNsPrefixes(m);
064: }
065:
066: /**
067: Load all the classes which are objects of any (t, ja:loadClass, S)
068: statements in <code>m</code>. The order in which the classes are
069: loaded is not specified, and loading stops immediately if any class
070: cannot be loaded.
071: <p>
072: Contrast with <code>loadClasses(AssemblerGroup,Model)</code>,
073: which loads classes and assumes that those classes are assemblers to
074: be added to the group.
075: */
076: public static void loadArbitraryClasses(AssemblerGroup g, Model m) {
077: StmtIterator it = m.listStatements(null, JA.loadClass, ANY);
078: while (it.hasNext())
079: loadArbitraryClass(g, it.nextStatement());
080: }
081:
082: /**
083: @deprecated Use <code>loadAssemblerClasses</code> instead
084: (since it's explicit in what kinds of classes it loads).
085: */
086: public static void loadClasses(AssemblerGroup group, Model m) {
087: loadAssemblerClasses(group, m);
088: }
089:
090: /**
091: Load all the classes which are objects of any (t, ja:assembler, S) statements
092: in <code>m</code>. <code>group.implementWIth(t,c)</code> is called
093: for each statement, where <code>c</code> is an instance of the class named
094: by <code>S</code>. The order in which the classes are loaded is not
095: specified, and loading stops immediately if any class cannot be loaded.
096: */
097: public static void loadAssemblerClasses(AssemblerGroup group,
098: Model m) {
099: StmtIterator it = m.listStatements(ANY, JA.assembler, ANY);
100: while (it.hasNext())
101: loadAssemblerClass(group, it.nextStatement());
102: }
103:
104: /**
105: Load the class named by the object of <code>s</code>, run its
106: <code>whenRequiredByAssembler</code> method if any, and
107: register an <code>implementWith</code> for the subject of
108: <code>s</code> and an instance of the class.
109: */
110: private static void loadAssemblerClass(AssemblerGroup group,
111: Statement s) {
112: Class c = loadArbitraryClass(group, s);
113: runAnyAssemblerConstructor(group, s, c);
114: }
115:
116: /**
117: Load the class named by the object of <code>s</code> if necessary.
118: If that class has a static method <code>whenRequiredByAssembler</code>
119: with an <code>AssemblerGroup</code> argument, call that method
120: passing it <code>ag</code>.
121: */
122: private static Class loadArbitraryClass(AssemblerGroup ag,
123: Statement s) {
124: Class loaded = loadClassNamedBy(s);
125: try {
126: Method m = loaded.getDeclaredMethod(
127: "whenRequiredByAssembler",
128: new Class[] { AssemblerGroup.class });
129: m.invoke(null, new Object[] { ag });
130: } catch (NoSuchMethodException e) { /* that's OK */
131: } catch (Exception e) {
132: throw new JenaException(e);
133: }
134: return loaded;
135: }
136:
137: private static Class loadClassNamedBy(Statement s) {
138: try {
139: return Class.forName(getString(s));
140: } catch (Exception e) {
141: throw new JenaException(e);
142: }
143: }
144:
145: private static void runAnyAssemblerConstructor(
146: AssemblerGroup group, Statement s, Class c) {
147: try {
148: Resource type = s.getSubject();
149: Constructor con = getResourcedConstructor(c);
150: if (con == null)
151: establish(group, type, c.newInstance());
152: else
153: establish(group, type, con.newInstance(new Object[] { s
154: .getSubject() }));
155: } catch (Exception e) {
156: throw new JenaException(e);
157: }
158: }
159:
160: private static void establish(AssemblerGroup group, Resource type,
161: Object x) {
162: if (x instanceof Assembler)
163: group.implementWith(type, (Assembler) x);
164: else
165: throw new JenaException(
166: "constructed entity is not an Assembler: " + x);
167: }
168:
169: private static Constructor getResourcedConstructor(Class c) {
170: try {
171: return c.getConstructor(new Class[] { Resource.class });
172: } catch (SecurityException e) {
173: return null;
174: } catch (NoSuchMethodException e) {
175: return null;
176: }
177: }
178:
179: /**
180: Answer the most specific type of <code>root</code> that is a subclass of
181: ja:Object. If there are no candidate types, answer <code>givenType</code>.
182: If there is more than one type, throw a NoSpecificTypeException.
183: */
184: public static Resource findSpecificType(Resource root) {
185: return findSpecificType(root, JA.Object);
186: }
187:
188: /**
189: Answer the most specific type of <code>root</code> that is a subclass of
190: <code>givenType</code>. If there are no candidate types, answer
191: <code>givenType</code>. If there is more than one type, throw a
192: NoSpecificTypeException.
193: */
194: public static Resource findSpecificType(Resource root,
195: Resource baseType) {
196: Set types = findSpecificTypes(root, baseType);
197: if (types.size() == 1)
198: return (Resource) types.iterator().next();
199: if (types.size() == 0)
200: return baseType;
201: throw new AmbiguousSpecificTypeException(root, new ArrayList(
202: types));
203: }
204:
205: /**
206: Answer all the types of <code>root</code> which are subtypes of
207: <code>baseType</code> and which do not have subtypes which are
208: also types of <code>root</code>.
209: */
210: public static Set findSpecificTypes(Resource root, Resource baseType) {
211: Model desc = root.getModel();
212: List types = root.listProperties(RDF.type).mapWith(
213: Statement.Util.getObject).toList();
214: Set results = new HashSet();
215: for (int i = 0; i < types.size(); i += 1) {
216: Resource candidate = (Resource) types.get(i);
217: if (candidate.hasProperty(RDFS.subClassOf, baseType))
218: if (hasNoCompetingSubclass(types, candidate))
219: results.add(candidate);
220: }
221: return results;
222: }
223:
224: private static boolean hasNoCompetingSubclass(List types,
225: Resource candidate) {
226: for (int j = 0; j < types.size(); j += 1) {
227: Resource other = (Resource) types.get(j);
228: if (other.hasProperty(RDFS.subClassOf, candidate)
229: && !candidate.equals(other))
230: return false;
231: }
232: return true;
233: }
234:
235: /**
236: Answer the resource that is the object of the statement <code>s</code>. If
237: the object is not a resource, throw a BadObjectException with that statement.
238: */
239: public static Resource getResource(Statement s) {
240: RDFNode ob = s.getObject();
241: if (ob.isLiteral())
242: throw new BadObjectException(s);
243: return (Resource) ob;
244: }
245:
246: /**
247: Answer the plain string object of the statement <code>s</code>. If the
248: object is not a string literal, throw a BadObjectException with that statement.
249: */
250: public static String getString(Statement s) {
251: RDFNode ob = s.getObject();
252: if (ob.isResource())
253: throw new BadObjectException(s);
254: Literal L = (Literal) ob;
255: if (!L.getLanguage().equals(""))
256: throw new BadObjectException(s);
257: if (L.getDatatype() == null)
258: return L.getLexicalForm();
259: if (L.getDatatype() == XSDDatatype.XSDstring)
260: return L.getLexicalForm();
261: throw new BadObjectException(s);
262: }
263:
264: /**
265: Answer the String value of the literal <code>L</code>, which is the
266: object of the Statement <code>s</code>. If the literal is not an
267: XSD String or a plain string without a language code, throw a
268: BadObjectException.
269: */
270: public static String getString(Statement s, Literal L) {
271: if (!L.getLanguage().equals(""))
272: throw new BadObjectException(s);
273: if (L.getDatatype() == null)
274: return L.getLexicalForm();
275: if (L.getDatatype() == XSDDatatype.XSDstring)
276: return L.getLexicalForm();
277: throw new BadObjectException(s);
278: }
279:
280: /**
281: Answer a Set of the ja:Object resources in the full expansion of
282: the assembler specification model <code>model</code>.
283: */
284: public static Set findAssemblerRoots(Model model) {
285: return findAssemblerRoots(model, JA.Object);
286: }
287:
288: /**
289: Answer a Set of the objects in the full expansion of the assembler
290: specification <code>model</code> which have rdf:type <code>type</code>,
291: which <i>must</i> be a subtype of <code>ja:Object</code>.
292: */
293: public static Set findAssemblerRoots(Model model, Resource type) {
294: return fullModel(model).listResourcesWithProperty(RDF.type,
295: type).toSet();
296: }
297:
298: /**
299: Answer the single resource in <code>singleRoot</code> of type
300: <code>ja:Model</code>. Otherwise throw an exception.
301: */
302: public static Resource singleModelRoot(Model singleRoot) {
303: return singleRoot(singleRoot, JA.Model);
304: }
305:
306: /**
307: Answer the single resource in <code>singleRoot</code> of type
308: <code>type</code>. Otherwise throw an exception.
309: */
310: public static Resource singleRoot(Model singleRoot, Resource type) {
311: Set roots = findAssemblerRoots(singleRoot, type);
312: if (roots.size() == 1)
313: return (Resource) roots.iterator().next();
314: if (roots.size() == 0)
315: throw new BadDescriptionNoRootException(singleRoot, type);
316: throw new BadDescriptionMultipleRootsException(singleRoot, type);
317: }
318: }
319:
320: /*
321: * (c) Copyright 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP All rights
322: * reserved.
323: *
324: * Redistribution and use in source and binary forms, with or without
325: * modification, are permitted provided that the following conditions are met:
326: * 1. Redistributions of source code must retain the above copyright notice,
327: * this list of conditions and the following disclaimer. 2. Redistributions in
328: * binary form must reproduce the above copyright notice, this list of
329: * conditions and the following disclaimer in the documentation and/or other
330: * materials provided with the distribution. 3. The name of the author may not
331: * be used to endorse or promote products derived from this software without
332: * specific prior written permission.
333: *
334: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
335: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
336: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
337: * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
338: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
339: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
340: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
341: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
342: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
343: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
344: */
|