http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParser.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParser.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParser.java new file mode 100644 index 0000000..604d98a --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParser.java @@ -0,0 +1,502 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena; + +import static org.apache.juneau.internal.StringUtils.*; +import static org.apache.juneau.jena.Constants.*; +import static org.apache.juneau.jena.RdfCommonContext.*; + +import java.lang.reflect.*; +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.annotation.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.transform.*; + +import com.hp.hpl.jena.rdf.model.*; +import com.hp.hpl.jena.util.iterator.*; + +/** + * Parses RDF into POJOs. + * + * <h6 class='topic'>Configurable properties</h6> + * <p> + * Refer to <a class='doclink' href='package-summary.html#ParserConfigurableProperties'>Configurable Properties</a> + * for the entire list of configurable properties. + * + * <h6 class='topic'>Behavior-specific subclasses</h6> + * <p> + * The following direct subclasses are provided for language-specific parsers: + * <ul class='spaced-list'> + * <li>{@link RdfParser.Xml} - RDF/XML and RDF/XML-ABBREV. + * <li>{@link RdfParser.NTriple} - N-TRIPLE. + * <li>{@link RdfParser.Turtle} - TURTLE. + * <li>{@link RdfParser.N3} - N3. + * </ul> + * + * <h6 class='topic'>Additional Information</h6> + * <p> + * See <a class='doclink' href='package-summary.html#TOC'>RDF Overview</a> for an overview of RDF support in Juneau. + */ +@Consumes(value="text/xml+rdf") +public class RdfParser extends ReaderParser { + + /** Default XML parser, all default settings.*/ + public static final RdfParser DEFAULT_XML = new RdfParser.Xml().lock(); + + /** Default Turtle parser, all default settings.*/ + public static final RdfParser DEFAULT_TURTLE = new RdfParser.Turtle().lock(); + + /** Default N-Triple parser, all default settings.*/ + public static final RdfParser DEFAULT_NTRIPLE = new RdfParser.NTriple().lock(); + + /** Default N3 parser, all default settings.*/ + public static final RdfParser DEFAULT_N3 = new RdfParser.N3().lock(); + + + /** Consumes RDF/XML input */ + @Consumes("text/xml+rdf") + public static class Xml extends RdfParser { + /** Constructor */ + public Xml() { + setProperty(RDF_language, LANG_RDF_XML); + } + } + + /** Consumes N-Triple input */ + @Consumes(value="text/n-triple") + public static class NTriple extends RdfParser { + /** Constructor */ + public NTriple() { + setProperty(RDF_language, LANG_NTRIPLE); + } + } + + /** Consumes Turtle input */ + @Consumes(value="text/turtle") + public static class Turtle extends RdfParser { + /** Constructor */ + public Turtle() { + setProperty(RDF_language, LANG_TURTLE); + } + } + + /** Consumes N3 input */ + @Consumes(value="text/n3") + public static class N3 extends RdfParser { + /** Constructor */ + public N3() { + setProperty(RDF_language, LANG_N3); + } + } + + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override /* ReaderParser */ + protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { + + RdfParserSession s = (RdfParserSession)session; + + type = session.normalizeClassMeta(type); + + Model model = s.getModel(); + RDFReader r = s.getRdfReader(); + r.read(model, session.getReader(), null); + + List<Resource> roots = getRoots(s, model); + + // Special case where we're parsing a loose collection of resources. + if (s.isLooseCollections() && type.isCollectionOrArray()) { + Collection c = null; + if (type.isArray()) + c = new ArrayList(); + else + c = (type.canCreateNewInstance(session.getOuter()) ? (Collection<?>)type.newInstance(session.getOuter()) : new ObjectList(session)); + for (Resource resource : roots) + c.add(parseAnything(s, type.getElementType(), resource, session.getOuter())); + + if (type.isArray()) + return (T)session.toArray(type, c); + return (T)c; + } + + if (roots.isEmpty()) + return null; + if (roots.size() > 1) + throw new ParseException(session, "Too many root nodes found in model: {0}", roots.size()); + Resource resource = roots.get(0); + + return parseAnything(s, type, resource, session.getOuter()); + } + + /* + * Finds the roots in the model using either the "root" property to identify it, + * or by resorting to scanning the model for all nodes with no incoming predicates. + */ + private List<Resource> getRoots(RdfParserSession session, Model m) { + List<Resource> l = new LinkedList<Resource>(); + + // First try to find the root using the "http://www.apache.org/juneau/root" property. + Property root = m.createProperty(session.getJuneauNsUri(), RDF_juneauNs_ROOT); + for (ResIterator i = m.listResourcesWithProperty(root); i.hasNext();) + l.add(i.next()); + + if (! l.isEmpty()) + return l; + + // Otherwise, we need to find all resources that aren't objects. + // We want to explicitly ignore statements where the subject + // and object are the same node. + Set<RDFNode> objects = new HashSet<RDFNode>(); + for (StmtIterator i = m.listStatements(); i.hasNext();) { + Statement st = i.next(); + RDFNode subject = st.getSubject(); + RDFNode object = st.getObject(); + if (object.isResource() && ! object.equals(subject)) + objects.add(object); + } + for (ResIterator i = m.listSubjects(); i.hasNext();) { + Resource r = i.next(); + if (! objects.contains(r)) + l.add(r); + } + return l; + } + + private <T> BeanMap<T> parseIntoBeanMap(RdfParserSession session, Resource r2, BeanMap<T> m) throws Exception { + BeanMeta<T> bm = m.getMeta(); + RdfBeanMeta rbm = bm.getExtendedMeta(RdfBeanMeta.class); + if (rbm.hasBeanUri() && r2.getURI() != null) + rbm.getBeanUriProperty().set(m, r2.getURI()); + Property subTypeIdProperty = null; + BeanPropertyMeta stp = bm.getSubTypeProperty(); + if (stp != null) { + subTypeIdProperty = session.getProperty(stp.getName()); + Statement st = r2.getProperty(subTypeIdProperty); + if (st == null) + throw new ParseException(session, "Could not find subtype ID property for bean of type ''{0}''", m.getClassMeta()); + String subTypeId = st.getLiteral().getString(); + stp.set(m, subTypeId); + } + for (StmtIterator i = r2.listProperties(); i.hasNext();) { + Statement st = i.next(); + Property p = st.getPredicate(); + if (p.equals(subTypeIdProperty)) + continue; + String key = session.decodeString(p.getLocalName()); + BeanPropertyMeta pMeta = m.getPropertyMeta(key); + session.setCurrentProperty(pMeta); + if (pMeta != null) { + RDFNode o = st.getObject(); + ClassMeta<?> cm = pMeta.getClassMeta(); + if (cm.isCollectionOrArray() && isMultiValuedCollections(session, pMeta)) { + ClassMeta<?> et = cm.getElementType(); + Object value = parseAnything(session, et, o, m.getBean(false)); + setName(et, value, key); + pMeta.add(m, value); + } else { + Object value = parseAnything(session, cm, o, m.getBean(false)); + setName(cm, value, key); + pMeta.set(m, value); + } + } else if (! (p.equals(session.getRootProperty()) || p.equals(session.getClassProperty()) || p.equals(subTypeIdProperty))) { + if (bm.isSubTyped()) { + RDFNode o = st.getObject(); + Object value = parseAnything(session, object(), o, m.getBean(false)); + m.put(key, value); + } else { + onUnknownProperty(session, key, m, -1, -1); + } + } + session.setCurrentProperty(null); + } + return m; + } + + private boolean isMultiValuedCollections(RdfParserSession session, BeanPropertyMeta pMeta) { + if (pMeta != null && pMeta.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat() != RdfCollectionFormat.DEFAULT) + return pMeta.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat() == RdfCollectionFormat.MULTI_VALUED; + return session.getCollectionFormat() == RdfCollectionFormat.MULTI_VALUED; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private <T> T parseAnything(RdfParserSession session, ClassMeta<T> eType, RDFNode n, Object outer) throws Exception { + + if (eType == null) + eType = (ClassMeta<T>)object(); + PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap(); + ClassMeta<?> sType = eType.getSerializedClassMeta(); + session.setCurrentClass(sType); + + if (! sType.canCreateNewInstance(outer)) { + if (n.isResource()) { + Statement st = n.asResource().getProperty(session.getClassProperty()); + if (st != null) { + String c = st.getLiteral().getString(); + sType = eType = (ClassMeta<T>)session.getClassMetaFromString(c); + } + } + } + + Object o = null; + if (n.isResource() && n.asResource().getURI() != null && n.asResource().getURI().equals(RDF_NIL)) { + // Do nothing. Leave o == null. + } else if (sType.isObject()) { + if (n.isLiteral()) { + o = n.asLiteral().getValue(); + if (o instanceof String) { + o = session.decodeString(o); + } + } + else if (n.isResource()) { + Resource r = n.asResource(); + if (session.wasAlreadyProcessed(r)) + o = r.getURI(); + else if (r.getProperty(session.getValueProperty()) != null) { + o = parseAnything(session, object(), n.asResource().getProperty(session.getValueProperty()).getObject(), outer); + } else if (isSeq(session, r)) { + o = new ObjectList(session); + parseIntoCollection(session, r.as(Seq.class), (Collection)o, sType.getElementType()); + } else if (isBag(session, r)) { + o = new ObjectList(session); + parseIntoCollection(session, r.as(Bag.class), (Collection)o, sType.getElementType()); + } else if (r.canAs(RDFList.class)) { + o = new ObjectList(session); + parseIntoCollection(session, r.as(RDFList.class), (Collection)o, sType.getElementType()); + } else { + // If it has a URI and no child properties, we interpret this as an + // external resource, and convert it to just a URL. + String uri = r.getURI(); + if (uri != null && ! r.listProperties().hasNext()) { + o = r.getURI(); + } else { + o = new ObjectMap(session); + parseIntoMap(session, r, (Map)o, null, null); + } + } + } else { + throw new ParseException(session, "Unrecognized node type ''{0}'' for object", n); + } + } else if (sType.isBoolean()) { + o = session.convertToType(getValue(session, n, outer), boolean.class); + } else if (sType.isCharSequence()) { + o = session.decodeString(getValue(session, n, outer)); + } else if (sType.isChar()) { + o = session.decodeString(getValue(session, n, outer)).charAt(0); + } else if (sType.isNumber()) { + o = parseNumber(getValue(session, n, outer).toString(), (Class<? extends Number>)sType.getInnerClass()); + } else if (sType.isMap()) { + Resource r = n.asResource(); + if (session.wasAlreadyProcessed(r)) + return null; + Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(session)); + o = parseIntoMap(session, r, m, eType.getKeyType(), eType.getValueType()); + } else if (sType.isCollectionOrArray()) { + if (sType.isArray()) + o = new ArrayList(); + else + o = (sType.canCreateNewInstance(outer) ? (Collection<?>)sType.newInstance(outer) : new ObjectList(session)); + Resource r = n.asResource(); + if (session.wasAlreadyProcessed(r)) + return null; + if (isSeq(session, r)) { + parseIntoCollection(session, r.as(Seq.class), (Collection)o, sType.getElementType()); + } else if (isBag(session, r)) { + parseIntoCollection(session, r.as(Bag.class), (Collection)o, sType.getElementType()); + } else if (r.canAs(RDFList.class)) { + parseIntoCollection(session, r.as(RDFList.class), (Collection)o, sType.getElementType()); + } else { + throw new ParseException("Unrecognized node type ''{0}'' for collection", n); + } + if (sType.isArray()) + o = session.toArray(sType, (Collection)o); + } else if (sType.canCreateNewInstanceFromObjectMap(outer)) { + Resource r = n.asResource(); + if (session.wasAlreadyProcessed(r)) + return null; + Map m = new ObjectMap(session); + parseIntoMap(session, r, m, eType.getKeyType(), eType.getValueType()); + o = sType.newInstanceFromObjectMap(outer, (ObjectMap)m); + } else if (sType.canCreateNewBean(outer)) { + Resource r = n.asResource(); + if (session.wasAlreadyProcessed(r)) + return null; + BeanMap<?> bm = session.newBeanMap(outer, sType.getInnerClass()); + o = parseIntoBeanMap(session, r, bm).getBean(); + } else if (sType.isUri() && n.isResource()) { + o = sType.newInstanceFromString(outer, session.decodeString(n.asResource().getURI())); + } else if (sType.canCreateNewInstanceFromString(outer)) { + o = sType.newInstanceFromString(outer, session.decodeString(getValue(session, n, outer))); + } else if (sType.canCreateNewInstanceFromNumber(outer)) { + o = sType.newInstanceFromNumber(session, outer, parseNumber(getValue(session, n, outer).toString(), sType.getNewInstanceFromNumberClass())); + } else { + throw new ParseException("Class ''{0}'' could not be instantiated. Reason: ''{1}''", sType.getInnerClass().getName(), sType.getNotABeanReason()); + } + + if (transform != null && o != null) + o = transform.unswap(session, o, eType); + + if (outer != null) + setParent(eType, o, outer); + + return (T)o; + } + + private boolean isSeq(RdfParserSession session, RDFNode n) { + if (n.isResource()) { + Statement st = n.asResource().getProperty(session.getTypeProperty()); + if (st != null) + return RDF_SEQ.equals(st.getResource().getURI()); + } + return false; + } + + private boolean isBag(RdfParserSession session, RDFNode n) { + if (n.isResource()) { + Statement st = n.asResource().getProperty(session.getTypeProperty()); + if (st != null) + return RDF_BAG.equals(st.getResource().getURI()); + } + return false; + } + + private Object getValue(RdfParserSession session, RDFNode n, Object outer) throws Exception { + if (n.isLiteral()) + return n.asLiteral().getValue(); + if (n.isResource()) { + Statement st = n.asResource().getProperty(session.getValueProperty()); + if (st != null) { + n = st.getObject(); + if (n.isLiteral()) + return n.asLiteral().getValue(); + return parseAnything(session, object(), st.getObject(), outer); + } + } + throw new ParseException(session, "Unknown value type for node ''{0}''", n); + } + + private <K,V> Map<K,V> parseIntoMap(RdfParserSession session, Resource r, Map<K,V> m, ClassMeta<K> keyType, ClassMeta<V> valueType) throws Exception { + // Add URI as "uri" to generic maps. + if (r.getURI() != null) { + K uri = convertAttrToType(session, m, "uri", keyType); + V value = convertAttrToType(session, m, r.getURI(), valueType); + m.put(uri, value); + } + for (StmtIterator i = r.listProperties(); i.hasNext();) { + Statement st = i.next(); + Property p = st.getPredicate(); + String key = p.getLocalName(); + if (! (key.equals("root") && p.getURI().equals(session.getJuneauNsUri()))) { + key = session.decodeString(key); + RDFNode o = st.getObject(); + K key2 = convertAttrToType(session, m, key, keyType); + V value = parseAnything(session, valueType, o, m); + setName(valueType, value, key); + m.put(key2, value); + } + + } + // TODO Auto-generated method stub + return m; + } + + private <E> Collection<E> parseIntoCollection(RdfParserSession session, Container c, Collection<E> l, ClassMeta<E> et) throws Exception { + for (NodeIterator ni = c.iterator(); ni.hasNext();) { + E e = parseAnything(session, et, ni.next(), l); + l.add(e); + } + return l; + } + + private <E> Collection<E> parseIntoCollection(RdfParserSession session, RDFList list, Collection<E> l, ClassMeta<E> et) throws Exception { + for (ExtendedIterator<RDFNode> ni = list.iterator(); ni.hasNext();) { + E e = parseAnything(session, et, ni.next(), l); + l.add(e); + } + return l; + } + + //-------------------------------------------------------------------------------- + // Overridden methods + //-------------------------------------------------------------------------------- + + @Override /* Parser */ + public RdfParserSession createSession(Object input, ObjectMap op, Method javaMethod, Object outer, Locale locale, TimeZone timeZone) { + return new RdfParserSession(getContext(RdfParserContext.class), op, input, javaMethod, outer, locale, timeZone); + } + + @Override /* CoreApi */ + public RdfParser setProperty(String property, Object value) throws LockedException { + super.setProperty(property, value); + return this; + } + + @Override /* CoreApi */ + public RdfParser setProperties(ObjectMap properties) throws LockedException { + super.setProperties(properties); + return this; + } + + @Override /* CoreApi */ + public RdfParser addNotBeanClasses(Class<?>...classes) throws LockedException { + super.addNotBeanClasses(classes); + return this; + } + + @Override /* CoreApi */ + public RdfParser addBeanFilters(Class<?>...classes) throws LockedException { + super.addBeanFilters(classes); + return this; + } + + @Override /* CoreApi */ + public RdfParser addPojoSwaps(Class<?>...classes) throws LockedException { + super.addPojoSwaps(classes); + return this; + } + + @Override /* CoreApi */ + public RdfParser addToDictionary(Class<?>...classes) throws LockedException { + super.addToDictionary(classes); + return this; + } + + @Override /* CoreApi */ + public <T> RdfParser addImplClass(Class<T> interfaceClass, Class<? extends T> implClass) throws LockedException { + super.addImplClass(interfaceClass, implClass); + return this; + } + + @Override /* CoreApi */ + public RdfParser setClassLoader(ClassLoader classLoader) throws LockedException { + super.setClassLoader(classLoader); + return this; + } + + @Override /* Lockable */ + public RdfParser lock() { + super.lock(); + return this; + } + + @Override /* Lockable */ + public RdfParser clone() { + try { + RdfParser c = (RdfParser)super.clone(); + return c; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); // Shouldn't happen + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParserContext.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParserContext.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParserContext.java new file mode 100644 index 0000000..eb0c1f9 --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParserContext.java @@ -0,0 +1,115 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.xml.*; + +/** + * Configurable properties on the {@link RdfParser} class. + * <p> + * Context properties are set by calling {@link ContextFactory#setProperty(String, Object)} on the context factory + * returned {@link CoreApi#getContextFactory()}. + * <p> + * The following convenience methods are also provided for setting context properties: + * <ul> + * <li>{@link RdfParser#setProperty(String,Object)} + * <li>{@link RdfParser#setProperties(ObjectMap)} + * <li>{@link RdfParser#addNotBeanClasses(Class[])} + * <li>{@link RdfParser#addBeanFilters(Class[])} + * <li>{@link RdfParser#addPojoSwaps(Class[])} + * <li>{@link RdfParser#addToDictionary(Class[])} + * <li>{@link RdfParser#addImplClass(Class,Class)} + * </ul> + * <p> + * See {@link ContextFactory} for more information about context properties. + * + * <h6 class='topic' id='ConfigProperties'>Configurable properties on the RDF parsers</h6> + * <table class='styled' style='border-collapse: collapse;'> + * <tr><th>Setting name</th><th>Description</th><th>Data type</th><th>Default value</th><th>Session overridable</th></tr> + * <tr> + * <td>{@link #RDF_trimWhitespace}</td> + * <td>Trim whitespace from text elements.</td> + * <td><code>Boolean</code></td> + * <td><jk>false</jk></td> + * <td><jk>true</jk></td> + * </tr> + * </table> + * + * <h6 class='topic' id='ConfigProperties'>Configurable properties inherited by the RDF parsers</h6> + * <ul class='javahierarchy'> + * <li class='c'><a class='doclink' href='../BeanContext.html#ConfigProperties'>BeanContext</a> - Properties associated with handling beans on serializers and parsers. + * <ul> + * <li class='c'><a class='doclink' href='../parser/ParserContext.html#ConfigProperties'>ParserContext</a> - Configurable properties common to all parsers. + * <ul> + * <li class='i'><a class='doclink' href='RdfCommonContext.html#ConfigProperties'>RdfCommonContext</a> - Configurable properties common to the RDF serializers and parsers. + * </ul> + * </ul> + * </ul> + */ +public final class RdfParserContext extends ParserContext implements RdfCommonContext { + + /** + * <b>Configuration property:</b> Trim whitespace from text elements. + * <p> + * <ul> + * <li><b>Name:</b> <js>"RdfParser.trimWhitespace"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * <p> + * If <jk>true</jk>, whitespace in text elements will be automatically trimmed. + */ + public static final String RDF_trimWhitespace = "RdfParser.trimWhitespace"; + + final boolean trimWhitespace, looseCollections; + final String rdfLanguage; + final Namespace juneauNs, juneauBpNs; + final RdfCollectionFormat collectionFormat; + final Map<String,Object> jenaSettings = new HashMap<String,Object>(); + + /** + * Constructor. + * <p> + * Typically only called from {@link ContextFactory#getContext(Class)}. + * + * @param cf The factory that created this context. + */ + public RdfParserContext(ContextFactory cf) { + super(cf); + trimWhitespace = cf.getProperty(RDF_trimWhitespace, boolean.class, false); + looseCollections = cf.getProperty(RDF_looseCollections, boolean.class, false); + rdfLanguage = cf.getProperty(RDF_language, String.class, "RDF/XML-ABBREV"); + juneauNs = cf.getProperty(RDF_juneauNs, Namespace.class, new Namespace("j", "http://www.apache.org/juneau/")); + juneauBpNs = cf.getProperty(RDF_juneauBpNs, Namespace.class, new Namespace("j", "http://www.apache.org/juneaubp/")); + collectionFormat = cf.getProperty(RDF_collectionFormat, RdfCollectionFormat.class, RdfCollectionFormat.DEFAULT); + } + + @Override /* Context */ + public ObjectMap asMap() { + return super.asMap() + .append("RdfParserContext", new ObjectMap() + .append("trimWhitespace", trimWhitespace) + .append("looseCollections", looseCollections) + .append("rdfLanguage", rdfLanguage) + .append("juneauNs", juneauNs) + .append("juneauBpNs", juneauBpNs) + .append("collectionFormat", collectionFormat) + ); + } +} + http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java new file mode 100644 index 0000000..2c73a00 --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java @@ -0,0 +1,234 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena; + +import static org.apache.juneau.jena.Constants.*; +import static org.apache.juneau.jena.RdfCommonContext.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.xml.*; + +import com.hp.hpl.jena.rdf.model.*; + +/** + * Session object that lives for the duration of a single use of {@link RdfParser}. + * <p> + * This class is NOT thread safe. It is meant to be discarded after one-time use. + */ +public class RdfParserSession extends ParserSession { + + private final String rdfLanguage; + private final Namespace juneauNs, juneauBpNs; + private final Property pRoot, pValue, pClass, pType; + private final Model model; + private final boolean trimWhitespace, looseCollections; + private final RDFReader rdfReader; + private final Set<Resource> urisVisited = new HashSet<Resource>(); + private final RdfCollectionFormat collectionFormat; + + /** + * Create a new session using properties specified in the context. + * + * @param ctx The context creating this session object. + * The context contains all the configuration settings for this object. + * @param input The input. Can be any of the following types: + * <ul> + * <li><jk>null</jk> + * <li>{@link Reader} + * <li>{@link CharSequence} + * <li>{@link InputStream} containing UTF-8 encoded text. + * <li>{@link File} containing system encoded text. + * </ul> + * @param op The override properties. + * These override any context properties defined in the context. + * @param javaMethod The java method that called this parser, usually the method in a REST servlet. + * @param outer The outer object for instantiating top-level non-static inner classes. + * @param locale The session locale. + * If <jk>null</jk>, then the locale defined on the context is used. + * @param timeZone The session timezone. + * If <jk>null</jk>, then the timezone defined on the context is used. + */ + protected RdfParserSession(RdfParserContext ctx, ObjectMap op, Object input, Method javaMethod, Object outer, Locale locale, TimeZone timeZone) { + super(ctx, op, input, javaMethod, outer, locale, timeZone); + ObjectMap jenaSettings = new ObjectMap(); + jenaSettings.putAll(ctx.jenaSettings); + if (op == null || op.isEmpty()) { + this.rdfLanguage = ctx.rdfLanguage; + this.juneauNs = ctx.juneauNs; + this.juneauBpNs = ctx.juneauBpNs; + this.trimWhitespace = ctx.trimWhitespace; + this.collectionFormat = ctx.collectionFormat; + this.looseCollections = ctx.looseCollections; + } else { + this.rdfLanguage = op.getString(RDF_language, ctx.rdfLanguage); + this.juneauNs = (op.containsKey(RDF_juneauNs) ? NamespaceFactory.parseNamespace(op.get(RDF_juneauNs)) : ctx.juneauNs); + this.juneauBpNs = (op.containsKey(RDF_juneauBpNs) ? NamespaceFactory.parseNamespace(op.get(RDF_juneauBpNs)) : ctx.juneauBpNs); + this.trimWhitespace = op.getBoolean(RdfParserContext.RDF_trimWhitespace, ctx.trimWhitespace); + this.collectionFormat = RdfCollectionFormat.valueOf(op.getString(RDF_collectionFormat, "DEFAULT")); + this.looseCollections = op.getBoolean(RDF_looseCollections, ctx.looseCollections); + } + this.model = ModelFactory.createDefaultModel(); + addModelPrefix(juneauNs); + addModelPrefix(juneauBpNs); + this.pRoot = model.createProperty(juneauNs.getUri(), RDF_juneauNs_ROOT); + this.pValue = model.createProperty(juneauNs.getUri(), RDF_juneauNs_VALUE); + this.pClass = model.createProperty(juneauNs.getUri(), RDF_juneauNs_CLASS); + this.pType = model.createProperty("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); + rdfReader = model.getReader(rdfLanguage); + + // Note: NTripleReader throws an exception if you try to set any properties on it. + if (! rdfLanguage.equals(LANG_NTRIPLE)) { + for (Map.Entry<String,Object> e : jenaSettings.entrySet()) + rdfReader.setProperty(e.getKey(), e.getValue()); + } + } + + /** + * Returns <jk>true</jk> if this resource was already visited. + * + * @param r The resource to check. + * @return <jk>true</jk> if this resource was already visited. + */ + public final boolean wasAlreadyProcessed(Resource r) { + return ! urisVisited.add(r); + } + + /** + * Returns the root property. + * + * @return The root property. + */ + public final Property getRootProperty() { + return pRoot; + } + + /** + * Returns the RDF property identifier <js>"value"</js>. + * + * @return The RDF property identifier <js>"value"</js>. + */ + public final Property getValueProperty() { + return pValue; + } + + /** + * Returns the RDF property identifier <js>"class"</js>. + * + * @return The RDF property identifier <js>"class"</js>. + */ + public final Property getClassProperty() { + return pClass; + } + + /** + * Returns the RDF property identifier <js>"type"</js>. + * + * @return The RDF property identifier <js>"type"</js>. + */ + public final Property getTypeProperty() { + return pType; + } + + /** + * Returns the RDF model being parsed into. + * + * @return The RDF model being parsed into. + */ + public final Model getModel() { + return model; + } + + /** + * Returns the RDF reader that's reading the model. + * + * @return The RDF reader that's reading the model. + */ + public final RDFReader getRdfReader() { + return rdfReader; + } + + /** + * Returns the {@link RdfCommonContext#RDF_collectionFormat} setting value for this session. + * + * @return The {@link RdfCommonContext#RDF_collectionFormat} setting value for this session. + */ + public final RdfCollectionFormat getCollectionFormat() { + return collectionFormat; + } + + /** + * Returns the {@link RdfCommonContext#RDF_looseCollections} setting value for this session. + * + * @return The {@link RdfCommonContext#RDF_looseCollections} setting value for this session. + */ + public final boolean isLooseCollections() { + return looseCollections; + } + + /** + * Returns the Juneau namespace URI. + * + * @return The Juneau namespace URI. + */ + public final String getJuneauNsUri() { + return juneauNs.getUri(); + } + + /** + * Adds the specified namespace as a model prefix. + * + * @param ns The XML namespace. + */ + public final void addModelPrefix(Namespace ns) { + model.setNsPrefix(ns.getName(), ns.getUri()); + } + + /** + * Constructs a <code>Property</code> in the Juneau Bean namespace in this mode. + * + * @param name The property name. + * @return The new property object. + */ + public final Property getProperty(String name) { + return model.createProperty(juneauBpNs.getUri(), name); + } + + /** + * Decodes the specified string. + * <p> + * If {@link RdfParserContext#RDF_trimWhitespace} is <jk>true</jk>, the resulting string is trimmed before decoding. + * <p> + * If {@link #isTrimStrings()} is <jk>true</jk>, the resulting string is trimmed after decoding. + * + * @param o The string to trim. + * @return The trimmed string, or <jk>null</jk> if the string was <jk>null</jk>. + */ + public final String decodeString(Object o) { + if (o == null) + return null; + String s = o.toString(); + if (s.isEmpty()) + return s; + if (trimWhitespace) + s = s.trim(); + s = XmlUtils.decode(s, null); + if (isTrimStrings()) + s = s.trim(); + return s; + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java new file mode 100644 index 0000000..0728b39 --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java @@ -0,0 +1,466 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena; + +import static org.apache.juneau.jena.Constants.*; +import static org.apache.juneau.jena.RdfCommonContext.*; + +import java.lang.reflect.*; +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.annotation.*; +import org.apache.juneau.internal.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.transform.*; +import org.apache.juneau.xml.*; + +import com.hp.hpl.jena.rdf.model.*; + +/** + * Serializes POJOs to RDF. + * + * <h6 class='topic'>Configurable properties</h6> + * <p> + * Refer to <a class='doclink' href='package-summary.html#SerializerConfigurableProperties'>Configurable Properties</a> + * for the entire list of configurable properties. + * + * <h6 class='topic'>Behavior-specific subclasses</h6> + * <p> + * The following direct subclasses are provided for language-specific serializers: + * <ul> + * <li>{@link RdfSerializer.Xml} - RDF/XML. + * <li>{@link RdfSerializer.XmlAbbrev} - RDF/XML-ABBREV. + * <li>{@link RdfSerializer.NTriple} - N-TRIPLE. + * <li>{@link RdfSerializer.Turtle} - TURTLE. + * <li>{@link RdfSerializer.N3} - N3. + * </ul> + * + * <h6 class='topic'>Additional Information</h6> + * <p> + * See <a class='doclink' href='package-summary.html#TOC'>RDF Overview</a> for an overview of RDF support in Juneau. + */ +@SuppressWarnings({ "rawtypes", "unchecked" }) +@Produces(value="text/xml+rdf+abbrev", contentType="text/xml+rdf") +public class RdfSerializer extends WriterSerializer { + + /** Default RDF/XML serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_XML = new RdfSerializer.Xml().lock(); + + /** Default Abbreviated RDF/XML serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_XMLABBREV = new RdfSerializer.XmlAbbrev().lock(); + + /** Default Turtle serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_TURTLE = new RdfSerializer.Turtle().lock(); + + /** Default N-Triple serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_NTRIPLE = new RdfSerializer.NTriple().lock(); + + /** Default N3 serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_N3 = new RdfSerializer.N3().lock(); + + + /** Produces RDF/XML output */ + @Produces("text/xml+rdf") + public static class Xml extends RdfSerializer { + /** Constructor */ + public Xml() { + setProperty(RDF_language, LANG_RDF_XML); + } + } + + /** Produces Abbreviated RDF/XML output */ + @Produces(value="text/xml+rdf+abbrev", contentType="text/xml+rdf") + public static class XmlAbbrev extends RdfSerializer { + /** Constructor */ + public XmlAbbrev() { + setProperty(RDF_language, LANG_RDF_XML_ABBREV); + } + } + + /** Produces N-Triple output */ + @Produces("text/n-triple") + public static class NTriple extends RdfSerializer { + /** Constructor */ + public NTriple() { + setProperty(RDF_language, LANG_NTRIPLE); + } + } + + /** Produces Turtle output */ + @Produces("text/turtle") + public static class Turtle extends RdfSerializer { + /** Constructor */ + public Turtle() { + setProperty(RDF_language, LANG_TURTLE); + } + } + + /** Produces N3 output */ + @Produces("text/n3") + public static class N3 extends RdfSerializer { + /** Constructor */ + public N3() { + setProperty(RDF_language, LANG_N3); + } + } + + + @Override /* Serializer */ + protected void doSerialize(SerializerSession session, Object o) throws Exception { + + RdfSerializerSession s = (RdfSerializerSession)session; + + Model model = s.getModel(); + Resource r = null; + + ClassMeta<?> cm = session.getClassMetaForObject(o); + if (s.isLooseCollections() && cm != null && cm.isCollectionOrArray()) { + Collection c = s.sort(cm.isCollection() ? (Collection)o : toList(cm.getInnerClass(), o)); + for (Object o2 : c) + serializeAnything(s, o2, false, object(), "root", null, null); + } else { + RDFNode n = serializeAnything(s, o, false, object(), "root", null, null); + if (n.isLiteral()) { + r = model.createResource(); + r.addProperty(s.getValueProperty(), n); + } else { + r = n.asResource(); + } + + if (s.isAddRootProp()) + r.addProperty(s.getRootProp(), "true"); + } + + s.getRdfWriter().write(model, session.getWriter(), "http://unknown/"); + } + + private RDFNode serializeAnything(RdfSerializerSession session, Object o, boolean isURI, ClassMeta<?> eType, String attrName, BeanPropertyMeta bpm, Resource parentResource) throws SerializeException { + Model m = session.getModel(); + + ClassMeta<?> aType = null; // The actual type + ClassMeta<?> wType = null; // The wrapped type + ClassMeta<?> sType = object(); // The serialized type + + aType = session.push(attrName, o, eType); + + if (eType == null) + eType = object(); + + // Handle recursion + if (aType == null) { + o = null; + aType = object(); + } + + if (o != null) { + + if (aType.isDelegate()) { + wType = aType; + aType = ((Delegate)o).getClassMeta(); + } + + sType = aType.getSerializedClassMeta(); + + // Swap if necessary + PojoSwap swap = aType.getPojoSwap(); + if (swap != null) { + o = swap.swap(session, o); + + // If the getSwapClass() method returns Object, we need to figure out + // the actual type now. + if (sType.isObject()) + sType = session.getClassMetaForObject(o); + } + } else { + sType = eType.getSerializedClassMeta(); + } + + RDFNode n = null; + + if (o == null || sType.isChar() && ((Character)o).charValue() == 0) { + if (bpm != null) { + if (! session.isTrimNulls()) { + n = m.createResource(RDF_NIL); + } + } else { + n = m.createResource(RDF_NIL); + } + + } else if (sType.isUri() || isURI) { + n = m.createResource(getUri(session, o, null)); + + } else if (sType.isCharSequence() || sType.isChar()) { + n = m.createLiteral(session.encodeTextInvalidChars(o)); + + } else if (sType.isNumber() || sType.isBoolean()) { + if (! session.isAddLiteralTypes()) + n = m.createLiteral(o.toString()); + else + n = m.createTypedLiteral(o); + + } else if (sType.isMap() || (wType != null && wType.isMap())) { + if (o instanceof BeanMap) { + BeanMap bm = (BeanMap)o; + Object uri = null; + RdfBeanMeta rbm = (RdfBeanMeta)bm.getMeta().getExtendedMeta(RdfBeanMeta.class); + if (rbm.hasBeanUri()) + uri = rbm.getBeanUriProperty().get(bm); + String uri2 = getUri(session, uri, null); + n = m.createResource(uri2); + serializeBeanMap(session, bm, (Resource)n); + } else { + Map m2 = (Map)o; + n = m.createResource(); + serializeMap(session, m2, (Resource)n, sType); + } + + } else if (sType.hasToObjectMapMethod()) { + Map m2 = sType.toObjectMap(o); + n = m.createResource(); + serializeMap(session, m2, (Resource)n, sType); + + } else if (sType.isBean()) { + BeanMap bm = session.toBeanMap(o); + Object uri = null; + RdfBeanMeta rbm = (RdfBeanMeta)bm.getMeta().getExtendedMeta(RdfBeanMeta.class); + if (rbm.hasBeanUri()) + uri = rbm.getBeanUriProperty().get(bm); + String uri2 = getUri(session, uri, null); + n = m.createResource(uri2); + serializeBeanMap(session, bm, (Resource)n); + + } else if (sType.isCollectionOrArray() || (wType != null && wType.isCollection())) { + Collection c = session.sort(sType.isCollection() ? (Collection)o : toList(sType.getInnerClass(), o)); + RdfCollectionFormat f = session.getCollectionFormat(); + RdfClassMeta rcm = sType.getExtendedMeta(RdfClassMeta.class); + if (rcm.getCollectionFormat() != RdfCollectionFormat.DEFAULT) + f = rcm.getCollectionFormat(); + if (bpm != null && bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat() != RdfCollectionFormat.DEFAULT) + f = bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat(); + switch (f) { + case BAG: n = serializeToContainer(session, c, sType, m.createBag()); break; + case LIST: n = serializeToList(session, c, sType); break; + case MULTI_VALUED: serializeToMultiProperties(session, c, sType, bpm, attrName, parentResource); break; + default: n = serializeToContainer(session, c, sType, m.createSeq()); + } + } else { + n = m.createLiteral(session.encodeTextInvalidChars(session.toString(o))); + } + + if (session.isAddBeanTypeProperties() && n != null && n.isResource()) { + if (o != null && ! eType.equals(aType)) + n.asResource().addProperty(session.getClassProperty(), aType.toString()); + else if (o == null) + n.asResource().addProperty(session.getClassProperty(), eType.toString()); + } + + session.pop(); + + return n; + } + + private String getUri(RdfSerializerSession session, Object uri, Object uri2) { + String s = null; + if (uri != null) + s = uri.toString(); + if ((s == null || s.isEmpty()) && uri2 != null) + s = uri2.toString(); + if (s == null) + return null; + if (s.indexOf("://") == -1) { + String aUri = session.getAbsolutePathUriBase(); + String rUri = session.getRelativeUriBase(); + if (StringUtils.startsWith(s, '/')) { + if (aUri != null) + return aUri + s; + } else { + if (rUri != null) { + if (rUri.equals("/")) + return '/' + s; + return rUri + '/' + s; + } + } + } + return s; + } + + private void serializeMap(RdfSerializerSession session, Map m, Resource r, ClassMeta<?> type) throws SerializeException { + + m = session.sort(m); + + ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType(); + + ArrayList<Map.Entry<Object,Object>> l = new ArrayList<Map.Entry<Object,Object>>(m.entrySet()); + Collections.reverse(l); + for (Map.Entry<Object,Object> me : l) { + Object value = me.getValue(); + + Object key = session.generalize(me.getKey(), keyType); + + Namespace ns = session.getJuneauBpNs(); + Model model = session.getModel(); + Property p = model.createProperty(ns.getUri(), session.encodeElementName(session.toString(key))); + RDFNode n = serializeAnything(session, value, false, valueType, key == null ? null : session.toString(key), null, r); + if (n != null) + r.addProperty(p, n); + } + } + + private void serializeBeanMap(RdfSerializerSession session, BeanMap<?> m, Resource r) throws SerializeException { + List<BeanPropertyValue> l = m.getValues(session.isTrimNulls()); + Collections.reverse(l); + for (BeanPropertyValue bpv : l) { + BeanPropertyMeta pMeta = bpv.getMeta(); + ClassMeta<?> cMeta = pMeta.getClassMeta(); + + if (pMeta.getExtendedMeta(RdfBeanPropertyMeta.class).isBeanUri()) + continue; + + String key = bpv.getName(); + Object value = bpv.getValue(); + Throwable t = bpv.getThrown(); + if (t != null) + session.addBeanGetterWarning(pMeta, t); + + if (session.canIgnoreValue(cMeta, key, value)) + continue; + + BeanPropertyMeta bpm = bpv.getMeta(); + Namespace ns = bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getNamespace(); + if (ns == null && session.isUseXmlNamespaces()) + ns = bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace(); + if (ns == null) + ns = session.getJuneauBpNs(); + else if (session.isAutoDetectNamespaces()) + session.addModelPrefix(ns); + + Property p = session.getModel().createProperty(ns.getUri(), session.encodeElementName(key)); + RDFNode n = serializeAnything(session, value, pMeta.isUri(), cMeta, key, pMeta, r); + if (n != null) + r.addProperty(p, n); + } + } + + + private Container serializeToContainer(RdfSerializerSession session, Collection c, ClassMeta<?> type, Container list) throws SerializeException { + + ClassMeta<?> elementType = type.getElementType(); + for (Object e : c) { + RDFNode n = serializeAnything(session, e, false, elementType, null, null, null); + list = list.add(n); + } + return list; + } + + private RDFList serializeToList(RdfSerializerSession session, Collection c, ClassMeta<?> type) throws SerializeException { + ClassMeta<?> elementType = type.getElementType(); + List<RDFNode> l = new ArrayList<RDFNode>(c.size()); + for (Object e : c) { + l.add(serializeAnything(session, e, false, elementType, null, null, null)); + } + return session.getModel().createList(l.iterator()); + } + + private void serializeToMultiProperties(RdfSerializerSession session, Collection c, ClassMeta<?> sType, BeanPropertyMeta bpm, String attrName, Resource parentResource) throws SerializeException { + ClassMeta<?> elementType = sType.getElementType(); + for (Object e : c) { + Namespace ns = null; + if (bpm != null) { + ns = bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getNamespace(); + if (ns == null && session.isUseXmlNamespaces()) + ns = bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace(); + } + if (ns == null) + ns = session.getJuneauBpNs(); + else if (session.isAutoDetectNamespaces()) + session.addModelPrefix(ns); + RDFNode n2 = serializeAnything(session, e, false, elementType, null, null, null); + Property p = session.getModel().createProperty(ns.getUri(), session.encodeElementName(attrName)); + parentResource.addProperty(p, n2); + } + + } + + //-------------------------------------------------------------------------------- + // Overridden methods + //-------------------------------------------------------------------------------- + + @Override /* Serializer */ + public RdfSerializerSession createSession(Object output, ObjectMap op, Method javaMethod, Locale locale, TimeZone timeZone) { + return new RdfSerializerSession(getContext(RdfSerializerContext.class), op, output, javaMethod, locale, timeZone); + } + + @Override /* CoreApi */ + public RdfSerializer setProperty(String property, Object value) throws LockedException { + super.setProperty(property, value); + return this; + } + + @Override /* CoreApi */ + public RdfSerializer setProperties(ObjectMap properties) throws LockedException { + super.setProperties(properties); + return this; + } + + @Override /* CoreApi */ + public RdfSerializer addNotBeanClasses(Class<?>...classes) throws LockedException { + super.addNotBeanClasses(classes); + return this; + } + + @Override /* CoreApi */ + public RdfSerializer addBeanFilters(Class<?>...classes) throws LockedException { + super.addBeanFilters(classes); + return this; + } + + @Override /* CoreApi */ + public RdfSerializer addPojoSwaps(Class<?>...classes) throws LockedException { + super.addPojoSwaps(classes); + return this; + } + + @Override /* CoreApi */ + public RdfSerializer addToDictionary(Class<?>...classes) throws LockedException { + super.addToDictionary(classes); + return this; + } + + @Override /* CoreApi */ + public <T> RdfSerializer addImplClass(Class<T> interfaceClass, Class<? extends T> implClass) throws LockedException { + super.addImplClass(interfaceClass, implClass); + return this; + } + + @Override /* CoreApi */ + public RdfSerializer setClassLoader(ClassLoader classLoader) throws LockedException { + super.setClassLoader(classLoader); + return this; + } + + @Override /* Lockable */ + public RdfSerializer lock() { + super.lock(); + return this; + } + + @Override /* Lockable */ + public RdfSerializer clone() { + try { + return (RdfSerializer)super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); // Shouldn't happen + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerContext.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerContext.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerContext.java new file mode 100644 index 0000000..fec2789 --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerContext.java @@ -0,0 +1,196 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.xml.*; + +/** + * Configurable properties on the {@link RdfSerializer} class. + * <p> + * Context properties are set by calling {@link ContextFactory#setProperty(String, Object)} on the context factory + * returned {@link CoreApi#getContextFactory()}. + * <p> + * The following convenience methods are also provided for setting context properties: + * <ul> + * <li>{@link RdfSerializer#setProperty(String,Object)} + * <li>{@link RdfSerializer#setProperties(ObjectMap)} + * <li>{@link RdfSerializer#addNotBeanClasses(Class[])} + * <li>{@link RdfSerializer#addBeanFilters(Class[])} + * <li>{@link RdfSerializer#addPojoSwaps(Class[])} + * <li>{@link RdfSerializer#addToDictionary(Class[])} + * <li>{@link RdfSerializer#addImplClass(Class,Class)} + * </ul> + * <p> + * See {@link ContextFactory} for more information about context properties. + * + * <h6 class='topic' id='ConfigProperties'>Configurable properties on the RDF serializers</h6> + * <table class='styled' style='border-collapse: collapse;'> + * <tr><th>Setting name</th><th>Description</th><th>Data type</th><th>Default value</th><th>Session overridable</th></tr> + * <tr> + * <td>{@link #RDF_addLiteralTypes}</td> + * <td>Add XSI data types to non-<code>String</code> literals.</td> + * <td><code>Boolean</code></td> + * <td><jk>false</jk></td> + * <td><jk>true</jk></td> + * </tr> + * <tr> + * <td>{@link #RDF_addRootProperty}</td> + * <td>Add RDF root identifier property to root node.</td> + * <td><code>Boolean</code></td> + * <td><jk>false</jk></td> + * <td><jk>true</jk></td> + * </tr> + * <tr> + * <td>{@link #RDF_autoDetectNamespaces}</td> + * <td>Auto-detect namespace usage.</td> + * <td><code>Boolean</code></td> + * <td><jk>true</jk></td> + * <td><jk>true</jk></td> + * </tr> + * <tr> + * <td>{@link #RDF_namespaces}</td> + * <td>Default namespaces.</td> + * <td><code>List<{@link Namespace}></code></td> + * <td>empty list</td> + * <td><jk>true</jk></td> + * </tr> + * </table> + * + * <h6 class='topic' id='ConfigProperties'>Configurable properties inherited by the RDF serializers</h6> + * <ul class='javahierarchy'> + * <li class='c'><a class='doclink' href='../BeanContext.html#ConfigProperties'>BeanContext</a> - Properties associated with handling beans on serializers and parsers. + * <ul> + * <li class='c'><a class='doclink' href='../serializer/SerializerContext.html#ConfigProperties'>SerializerContext</a> - Configurable properties common to all serializers. + * <ul> + * <li class='c'><a class='doclink' href='RdfCommonContext.html#ConfigProperties'>RdfCommonContext</a> - Configurable properties common to the RDF serializers and parsers. + * </ul> + * </ul> + * </ul> + */ +public final class RdfSerializerContext extends SerializerContext implements RdfCommonContext { + + /** + * <b>Configuration property:</b> Add XSI data types to non-<code>String</code> literals. + * <p> + * <ul> + * <li><b>Name:</b> <js>"RdfSerializer.addLiteralTypes"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + */ + public static final String RDF_addLiteralTypes = "RdfSerializer.addLiteralTypes"; + + /** + * <b>Configuration property:</b> Add RDF root identifier property to root node. + * <p> + * <ul> + * <li><b>Name:</b> <js>"RdfSerializer.addRootProperty"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * <p> + * When enabled an RDF property <code>http://www.apache.org/juneau/root</code> is added with a value of <js>"true"</js> + * to identify the root node in the graph. + * This helps locate the root node during parsing. + * <p> + * If disabled, the parser has to search through the model to find any resources without + * incoming predicates to identify root notes, which can introduce a considerable performance + * degradation. + */ + public static final String RDF_addRootProperty = "RdfSerializer.addRootProperty"; + + /** + * <b>Configuration property:</b> Auto-detect namespace usage. + * <p> + * <ul> + * <li><b>Name:</b> <js>"RdfSerializer.autoDetectNamespaces"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>true</jk> + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * <p> + * Detect namespace usage before serialization. + * <p> + * If enabled, then the data structure will first be crawled looking for + * namespaces that will be encountered before the root element is + * serialized. + */ + public static final String RDF_autoDetectNamespaces = "RdfSerializer.autoDetectNamespaces"; + + /** + * <b>Configuration property:</b> Default namespaces. + * <p> + * <ul> + * <li><b>Name:</b> <js>"RdfSerializer.namespaces.list"</js> + * <li><b>Data type:</b> <code>List<{@link Namespace}></code> + * <li><b>Default:</b> empty list + * <li><b>Session-overridable:</b> <jk>true</jk> + * </ul> + * <p> + * The default list of namespaces associated with this serializer. + */ + public static final String RDF_namespaces = "RdfSerializer.namespaces.list"; + + + final boolean addLiteralTypes, addRootProperty, useXmlNamespaces, looseCollections, autoDetectNamespaces; + final String rdfLanguage; + final Namespace juneauNs; + final Namespace juneauBpNs; + final RdfCollectionFormat collectionFormat; + final Map<String,Object> jenaSettings = new HashMap<String,Object>(); + final Namespace[] namespaces; + + /** + * Constructor. + * <p> + * Typically only called from {@link ContextFactory#getContext(Class)}. + * + * @param cf The factory that created this context. + */ + public RdfSerializerContext(ContextFactory cf) { + super(cf); + addLiteralTypes = cf.getProperty(RDF_addLiteralTypes, boolean.class, false); + addRootProperty = cf.getProperty(RDF_addRootProperty, boolean.class, false); + useXmlNamespaces = cf.getProperty(RDF_useXmlNamespaces, boolean.class, true); + looseCollections = cf.getProperty(RDF_looseCollections, boolean.class, false); + autoDetectNamespaces = cf.getProperty(RDF_autoDetectNamespaces, boolean.class, true); + rdfLanguage = cf.getProperty(RDF_language, String.class, "RDF/XML-ABBREV"); + juneauNs = cf.getProperty(RDF_juneauNs, Namespace.class, new Namespace("j", "http://www.apache.org/juneau/")); + juneauBpNs = cf.getProperty(RDF_juneauBpNs, Namespace.class, new Namespace("jp", "http://www.apache.org/juneaubp/")); + collectionFormat = cf.getProperty(RDF_collectionFormat, RdfCollectionFormat.class, RdfCollectionFormat.DEFAULT); + namespaces = cf.getProperty(RDF_namespaces, Namespace[].class, new Namespace[0]); + } + + @Override /* Context */ + public ObjectMap asMap() { + return super.asMap() + .append("RdfSerializerContext", new ObjectMap() + .append("addLiteralTypes", addLiteralTypes) + .append("addRootProperty", addRootProperty) + .append("useXmlNamespaces", useXmlNamespaces) + .append("looseCollections", looseCollections) + .append("autoDetectNamespaces", autoDetectNamespaces) + .append("rdfLanguage", rdfLanguage) + .append("juneauNs", juneauNs) + .append("juneauBpNs", juneauBpNs) + .append("collectionFormat", collectionFormat) + .append("namespaces", namespaces) + ); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java new file mode 100644 index 0000000..d30f934 --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java @@ -0,0 +1,271 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena; + +import static org.apache.juneau.jena.Constants.*; +import static org.apache.juneau.jena.RdfCommonContext.*; +import static org.apache.juneau.jena.RdfSerializerContext.*; + +import java.lang.reflect.*; +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.json.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.xml.*; + +import com.hp.hpl.jena.rdf.model.*; + +/** + * Session object that lives for the duration of a single use of {@link RdfSerializer}. + * <p> + * This class is NOT thread safe. It is meant to be discarded after one-time use. + */ +public final class RdfSerializerSession extends SerializerSession { + + private final String rdfLanguage; + private final Namespace juneauNs, juneauBpNs; + private final boolean addLiteralTypes, addRootProperty, useXmlNamespaces, looseCollections, autoDetectNamespaces; + private final Property pRoot, pValue, pClass; + private final Model model; + private final RDFWriter writer; + private final RdfCollectionFormat collectionFormat; + private final Namespace[] namespaces; + + /** + * Create a new session using properties specified in the context. + * + * @param ctx The context creating this session object. + * The context contains all the configuration settings for this object. + * @param output The output object. See {@link JsonSerializerSession#getWriter()} for valid class types. + * @param op The override properties. + * These override any context properties defined in the context. + * @param javaMethod The java method that called this parser, usually the method in a REST servlet. + * @param locale The session locale. + * If <jk>null</jk>, then the locale defined on the context is used. + * @param timeZone The session timezone. + * If <jk>null</jk>, then the timezone defined on the context is used. + */ + protected RdfSerializerSession(RdfSerializerContext ctx, ObjectMap op, Object output, Method javaMethod, Locale locale, TimeZone timeZone) { + super(ctx, op, output, javaMethod, locale, timeZone); + ObjectMap jenaSettings = new ObjectMap(); + jenaSettings.put("rdfXml.tab", isUseIndentation() ? 2 : 0); + jenaSettings.put("rdfXml.attributeQuoteChar", Character.toString(getQuoteChar())); + jenaSettings.putAll(ctx.jenaSettings); + if (op == null || op.isEmpty()) { + this.rdfLanguage = ctx.rdfLanguage; + this.juneauNs = ctx.juneauNs; + this.juneauBpNs = ctx.juneauBpNs; + this.addLiteralTypes = ctx.addLiteralTypes; + this.addRootProperty = ctx.addRootProperty; + this.collectionFormat = ctx.collectionFormat; + this.looseCollections = ctx.looseCollections; + this.useXmlNamespaces = ctx.useXmlNamespaces; + this.autoDetectNamespaces = ctx.autoDetectNamespaces; + this.namespaces = ctx.namespaces; + } else { + this.rdfLanguage = op.getString(RDF_language, ctx.rdfLanguage); + this.juneauNs = (op.containsKey(RDF_juneauNs) ? NamespaceFactory.parseNamespace(op.get(RDF_juneauNs)) : ctx.juneauNs); + this.juneauBpNs = (op.containsKey(RDF_juneauBpNs) ? NamespaceFactory.parseNamespace(op.get(RDF_juneauBpNs)) : ctx.juneauBpNs); + this.addLiteralTypes = op.getBoolean(RDF_addLiteralTypes, ctx.addLiteralTypes); + this.addRootProperty = op.getBoolean(RDF_addRootProperty, ctx.addRootProperty); + for (Map.Entry<String,Object> e : op.entrySet()) { + String key = e.getKey(); + if (key.startsWith("Rdf.jena.")) + jenaSettings.put(key.substring(9), e.getValue()); + } + this.collectionFormat = RdfCollectionFormat.valueOf(op.getString(RDF_collectionFormat, "DEFAULT")); + this.looseCollections = op.getBoolean(RDF_looseCollections, ctx.looseCollections); + this.useXmlNamespaces = op.getBoolean(RDF_useXmlNamespaces, ctx.useXmlNamespaces); + this.autoDetectNamespaces = op.getBoolean(RDF_autoDetectNamespaces, ctx.autoDetectNamespaces); + this.namespaces = op.get(Namespace[].class, RDF_namespaces, ctx.namespaces); + } + this.model = ModelFactory.createDefaultModel(); + addModelPrefix(juneauNs); + addModelPrefix(juneauBpNs); + for (Namespace ns : this.namespaces) + addModelPrefix(ns); + this.pRoot = model.createProperty(juneauNs.getUri(), RDF_juneauNs_ROOT); + this.pValue = model.createProperty(juneauNs.getUri(), RDF_juneauNs_VALUE); + this.pClass = model.createProperty(juneauNs.getUri(), RDF_juneauNs_CLASS); + writer = model.getWriter(rdfLanguage); + + // Only apply properties with this prefix! + String propPrefix = RdfCommonContext.LANG_PROP_MAP.get(rdfLanguage); + if (propPrefix == null) + throw new RuntimeException("Unknown RDF language encountered: '"+rdfLanguage+"'"); + + for (Map.Entry<String,Object> e : jenaSettings.entrySet()) + if (e.getKey().startsWith(propPrefix)) + writer.setProperty(e.getKey().substring(propPrefix.length()), e.getValue()); + } + + /** + * Adds the specified namespace as a model prefix. + * + * @param ns The XML namespace. + */ + public void addModelPrefix(Namespace ns) { + model.setNsPrefix(ns.getName(), ns.getUri()); + } + + /** + * Returns the {@link RdfCommonContext#RDF_collectionFormat} setting value for this session. + * + * @return The {@link RdfCommonContext#RDF_collectionFormat} setting value for this session. + */ + public final RdfCollectionFormat getCollectionFormat() { + return collectionFormat; + } + + /** + * Returns the {@link RdfCommonContext#RDF_useXmlNamespaces} setting value for this session. + * + * @return The {@link RdfCommonContext#RDF_useXmlNamespaces} setting value for this session. + */ + public final boolean isUseXmlNamespaces() { + return useXmlNamespaces; + } + + /** + * Returns the {@link RdfCommonContext#RDF_looseCollections} setting value for this session. + * + * @return The {@link RdfCommonContext#RDF_looseCollections} setting value for this session. + */ + public final boolean isLooseCollections() { + return looseCollections; + } + + /** + * Returns the {@link RdfCommonContext#RDF_language} setting value for this session. + * + * @return The {@link RdfCommonContext#RDF_language} setting value for this session. + */ + public final String getRdfLanguage() { + return rdfLanguage; + } + + /** + * Returns the {@link RdfCommonContext#RDF_juneauNs} setting value for this session. + * + * @return The {@link RdfCommonContext#RDF_juneauNs} setting value for this session. + */ + public final Namespace getJuneauNs() { + return juneauNs; + } + + /** + * Returns the {@link RdfCommonContext#RDF_juneauBpNs} setting value for this session. + * + * @return The {@link RdfCommonContext#RDF_juneauBpNs} setting value for this session. + */ + public final Namespace getJuneauBpNs() { + return juneauBpNs; + } + + /** + * Returns the {@link RdfSerializerContext#RDF_addLiteralTypes} setting value for this session. + * + * @return The {@link RdfSerializerContext#RDF_addLiteralTypes} setting value for this session. + */ + public final boolean isAddLiteralTypes() { + return addLiteralTypes; + } + + /** + * Returns the {@link RdfSerializerContext#RDF_addRootProperty} setting value for this session. + * + * @return The {@link RdfSerializerContext#RDF_addRootProperty} setting value for this session. + */ + public final boolean isAddRootProp() { + return addRootProperty; + } + + /** + * Returns the {@link RdfSerializerContext#RDF_autoDetectNamespaces} setting value for this session. + * + * @return The {@link RdfSerializerContext#RDF_autoDetectNamespaces} setting value for this session. + */ + public final boolean isAutoDetectNamespaces() { + return autoDetectNamespaces; + } + + /** + * Returns the RDF property that identifies the root node in the RDF model. + * + * @return The RDF property that identifies the root node in the RDF model. + */ + public final Property getRootProp() { + return pRoot; + } + + /** + * Returns the RDF property that represents a value in the RDF model. + * + * @return The RDF property that represents a value in the RDF model. + */ + public final Property getValueProperty() { + return pValue; + } + + /** + * Returns the RDF property that represents a class in the RDF model. + * + * @return The RDF property that represents a class in the RDF model. + */ + public final Property getClassProperty() { + return pClass; + } + + /** + * Returns the RDF model being serialized. + * + * @return The RDF model being serialized. + */ + public final Model getModel() { + return model; + } + + /** + * Returns the RDF writer that's being serialized to. + * + * @return The RDF writer that's being serialized to. + */ + public final RDFWriter getRdfWriter() { + return writer; + } + + /** + * XML-encodes the specified string using the {@link XmlUtils#encodeTextInvalidChars(Object)} method. + * + * @param o The string being encoded. + * @return The encoded string, or <jk>null</jk> if the input was <jk>null</jk>. + */ + public final String encodeTextInvalidChars(Object o) { + if (o == null) + return null; + String s = toString(o); + return XmlUtils.encodeTextInvalidChars(s); + } + + /** + * XML-encoded the specified element name using the {@link XmlUtils#encodeElementName(Object)} method. + * + * @param o The string being encoded. + * @return The encoded string. + */ + public final String encodeElementName(Object o) { + String s = toString(o); + return XmlUtils.encodeElementName(s); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfUtils.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfUtils.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfUtils.java new file mode 100644 index 0000000..4377e2e --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/RdfUtils.java @@ -0,0 +1,91 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.jena.annotation.*; +import org.apache.juneau.xml.*; + +/** + * Utility classes. + */ +public class RdfUtils { + + /** + * Find the namespace given a list of <ja>@Rdf</ja> and <ja>@RdfSchema</ja> annotations. + * The annotations should be a child-to-parent ordering of annotations found on + * a class or method. + * + * @param rdfs The <code>@Rdf</code> annotations to search. + * @param schemas The list of known RDF schemas. + * @return The resolved namespace, or <jk>null</jk> if the namespace could not be resolved. + */ + public static Namespace findNamespace(List<Rdf> rdfs, List<RdfSchema> schemas) { + + for (Rdf rdf : rdfs) { + Namespace ns = findNamespace(rdf.prefix(), rdf.namespace(), rdfs, schemas); + if (ns != null) + return ns; + } + + for (RdfSchema schema : schemas) { + Namespace ns = findNamespace(schema.prefix(), schema.namespace(), null, schemas); + if (ns != null) + return ns; + } + + return null; + } + + private static Namespace findNamespace(String prefix, String ns, List<Rdf> rdfs, List<RdfSchema> schemas) { + + // If both prefix and namespace specified, use that Namespace mapping. + if (! (prefix.isEmpty() || ns.isEmpty())) + return NamespaceFactory.get(prefix, ns); + + // If only prefix specified, need to search for namespaceURI. + if (! prefix.isEmpty()) { + if (rdfs != null) + for (Rdf rdf2 : rdfs) + if (rdf2.prefix().equals(prefix) && ! rdf2.namespace().isEmpty()) + return NamespaceFactory.get(prefix, rdf2.namespace()); + for (RdfSchema schema : schemas) { + if (schema.prefix().equals(prefix) && ! schema.namespace().isEmpty()) + return NamespaceFactory.get(prefix, schema.namespace()); + for (RdfNs rdfNs : schema.rdfNs()) + if (rdfNs.prefix().equals(prefix)) + return NamespaceFactory.get(prefix, rdfNs.namespaceURI()); + } + throw new BeanRuntimeException("Found @Rdf.prefix annotation with no matching URI. prefix='"+prefix+"'"); + } + + // If only namespaceURI specified, need to search for prefix. + if (! ns.isEmpty()) { + if (rdfs != null) + for (Rdf rdf2 : rdfs) + if (rdf2.namespace().equals(ns) && ! rdf2.prefix().isEmpty()) + return NamespaceFactory.get(rdf2.prefix(), ns); + for (RdfSchema schema : schemas) { + if (schema.namespace().equals(ns) && ! schema.prefix().isEmpty()) + return NamespaceFactory.get(schema.prefix(), ns); + for (RdfNs rdfNs : schema.rdfNs()) + if (rdfNs.namespaceURI().equals(ns)) + return NamespaceFactory.get(rdfNs.prefix(), ns); + } + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/annotation/Rdf.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/annotation/Rdf.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/annotation/Rdf.java new file mode 100644 index 0000000..275514b --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/annotation/Rdf.java @@ -0,0 +1,71 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena.annotation; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +import org.apache.juneau.jena.*; + +/** + * Annotation for specifying options for RDF serializers. + * <p> + * Can be applied to Java packages, types, fields, and methods. + * <p> + * Can be used for the following: + * <ul class='spaced-list'> + * <li>Override the default behavior of how collections and arrays are serialized. + * </ul> + */ +@Documented +@Target({PACKAGE,TYPE,FIELD,METHOD}) +@Retention(RUNTIME) +@Inherited +public @interface Rdf { + + /** + * Sets the XML prefix of this property or class. + * <p> + * Must either be matched to a {@link #namespace()} annotation on the same object, parent object, or a {@link RdfNs} with the same name + * through the {@link RdfSchema#rdfNs()} annotation on the package. + * </p> + */ + String prefix() default ""; + + /** + * Sets the namespace URI of this property or class. + * <p> + * Must be matched with a {@link #prefix()} annotation on this object, a parent object, or a {@link RdfNs} with the same name + * through the {@link RdfSchema#rdfNs()} annotation on the package. + */ + String namespace() default ""; + + /** + * The format for how collections (e.g. lists and arrays) are serialized in RDF. + * @see RdfCollectionFormat + */ + RdfCollectionFormat collectionFormat() default RdfCollectionFormat.DEFAULT; + + /** + * Marks a bean property as a resource URI identifier for the bean. + * <p> + * Has the following effects on the following serializers: + * <ul class='spaced-list'> + * <li>{@link RdfSerializer} - Will be rendered as the value of the <js>"rdf:about"</js> attribute + * for the bean. + * </ul> + */ + boolean beanUri() default false; +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfNs.java ---------------------------------------------------------------------- diff --git a/juneau-core-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfNs.java b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfNs.java new file mode 100644 index 0000000..0bf66cf --- /dev/null +++ b/juneau-core-rdf/src/main/java/org/apache/juneau/jena/annotation/RdfNs.java @@ -0,0 +1,39 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * +// * with the License. You may obtain a copy of the License at * +// * * +// * http://www.apache.org/licenses/LICENSE-2.0 * +// * * +// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * +// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * +// * specific language governing permissions and limitations under the License. * +// *************************************************************************************************************************** +package org.apache.juneau.jena.annotation; + +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.*; + +/** + * Namespace name/URL mapping pair. + * <p> + * Used to identify a namespace/URI pair on a {@link RdfSchema#rdfNs()} annotation. + */ +@Documented +@Target({}) +@Retention(RUNTIME) +@Inherited +public @interface RdfNs { + + /** + * RDF namespace prefix. + */ + String prefix(); + + /** + * RDF namespace URL. + */ + String namespaceURI(); +}
