http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java new file mode 100644 index 0000000..267d06f --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java @@ -0,0 +1,434 @@ +// *************************************************************************************************************************** +// * 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.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.transform.*; +import org.apache.juneau.xml.*; + +import com.hp.hpl.jena.rdf.model.*; +import com.hp.hpl.jena.util.iterator.*; + +/** + * Session object that lives for the duration of a single use of {@link RdfParser}. + * + * <p> + * This class is NOT thread safe. + * It is typically discarded after one-time use although it can be reused against multiple inputs. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class RdfParserSession extends ReaderParserSession { + + private final String rdfLanguage; + private final Namespace juneauNs, juneauBpNs; + private final Property pRoot, pValue, pType, pRdfType; + 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 args + * Runtime session arguments. + */ + protected RdfParserSession(RdfParserContext ctx, ParserSessionArgs args) { + super(ctx, args); + ObjectMap jenaSettings = new ObjectMap(); + jenaSettings.putAll(ctx.jenaSettings); + ObjectMap p = getProperties(); + if (p.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 = p.getString(RDF_language, ctx.rdfLanguage); + this.juneauNs = (p.containsKey(RDF_juneauNs) ? NamespaceFactory.parseNamespace(p.get(RDF_juneauNs)) : ctx.juneauNs); + this.juneauBpNs = (p.containsKey(RDF_juneauBpNs) ? NamespaceFactory.parseNamespace(p.get(RDF_juneauBpNs)) : ctx.juneauBpNs); + this.trimWhitespace = p.getBoolean(RdfParserContext.RDF_trimWhitespace, ctx.trimWhitespace); + this.collectionFormat = RdfCollectionFormat.valueOf(p.getString(RDF_collectionFormat, "DEFAULT")); + this.looseCollections = p.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.pType = model.createProperty(juneauBpNs.getUri(), RDF_juneauNs_TYPE); + this.pRdfType = 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()); + } + } + + @Override /* ReaderParserSession */ + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + + RDFReader r = rdfReader; + r.read(model, pipe.getBufferedReader(), null); + + List<Resource> roots = getRoots(model); + + // Special case where we're parsing a loose collection of resources. + if (looseCollections && type.isCollectionOrArray()) { + Collection c = null; + if (type.isArray() || type.isArgs()) + c = new ArrayList(); + else + c = ( + type.canCreateNewInstance(getOuter()) + ? (Collection<?>)type.newInstance(getOuter()) + : new ObjectList(this) + ); + + int argIndex = 0; + for (Resource resource : roots) + c.add(parseAnything(type.isArgs() ? type.getArg(argIndex++) : type.getElementType(), resource, + getOuter(), null)); + + if (type.isArray() || type.isArgs()) + return (T)toArray(type, c); + return (T)c; + } + + if (roots.isEmpty()) + return null; + if (roots.size() > 1) + throw new ParseException(loc(), "Too many root nodes found in model: {0}", roots.size()); + Resource resource = roots.get(0); + + return parseAnything(type, resource, getOuter(), null); + } + + private final void addModelPrefix(Namespace ns) { + model.setNsPrefix(ns.getName(), ns.getUri()); + } + + /* + * Decodes the specified string. + * If {@link RdfParserContext#RDF_trimWhitespace} is <jk>true</jk>, the resulting string is trimmed before decoding. + * If {@link #isTrimStrings()} is <jk>true</jk>, the resulting string is trimmed after decoding. + */ + private 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; + } + + /* + * 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(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(juneauNs.getUri(), 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(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, null, r2.getURI()); + for (StmtIterator i = r2.listProperties(); i.hasNext();) { + Statement st = i.next(); + Property p = st.getPredicate(); + String key = decodeString(p.getLocalName()); + BeanPropertyMeta pMeta = m.getPropertyMeta(key); + setCurrentProperty(pMeta); + if (pMeta != null) { + RDFNode o = st.getObject(); + ClassMeta<?> cm = pMeta.getClassMeta(); + if (cm.isCollectionOrArray() && isMultiValuedCollections(pMeta)) { + ClassMeta<?> et = cm.getElementType(); + Object value = parseAnything(et, o, m.getBean(false), pMeta); + setName(et, value, key); + pMeta.add(m, key, value); + } else { + Object value = parseAnything(cm, o, m.getBean(false), pMeta); + setName(cm, value, key); + pMeta.set(m, key, value); + } + } else if (! (p.equals(pRoot) || p.equals(pType))) { + onUnknownProperty(null, key, m, -1, -1); + } + setCurrentProperty(null); + } + return m; + } + + private boolean isMultiValuedCollections(BeanPropertyMeta pMeta) { + if (pMeta != null && pMeta.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat() != RdfCollectionFormat.DEFAULT) + return pMeta.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat() == RdfCollectionFormat.MULTI_VALUED; + return collectionFormat == RdfCollectionFormat.MULTI_VALUED; + } + + private <T> T parseAnything(ClassMeta<T> eType, RDFNode n, Object outer, BeanPropertyMeta pMeta) throws Exception { + + if (eType == null) + eType = (ClassMeta<T>)object(); + PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap(); + ClassMeta<?> sType = eType.getSerializedClassMeta(); + setCurrentClass(sType); + + if (! sType.canCreateNewInstance(outer)) { + if (n.isResource()) { + Statement st = n.asResource().getProperty(pType); + if (st != null) { + String c = st.getLiteral().getString(); + ClassMeta tcm = getClassMeta(c, pMeta, eType); + if (tcm != null) + sType = eType = tcm; + } + } + } + + 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 = decodeString(o); + } + } + else if (n.isResource()) { + Resource r = n.asResource(); + if (! urisVisited.add(r)) + o = r.getURI(); + else if (r.getProperty(pValue) != null) { + o = parseAnything(object(), n.asResource().getProperty(pValue).getObject(), outer, null); + } else if (isSeq(r)) { + o = new ObjectList(this); + parseIntoCollection(r.as(Seq.class), (Collection)o, sType, pMeta); + } else if (isBag(r)) { + o = new ObjectList(this); + parseIntoCollection(r.as(Bag.class), (Collection)o, sType, pMeta); + } else if (r.canAs(RDFList.class)) { + o = new ObjectList(this); + parseIntoCollection(r.as(RDFList.class), (Collection)o, sType, pMeta); + } 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 { + ObjectMap m2 = new ObjectMap(this); + parseIntoMap(r, m2, null, null, pMeta); + o = cast(m2, pMeta, eType); + } + } + } else { + throw new ParseException(loc(), "Unrecognized node type ''{0}'' for object", n); + } + } else if (sType.isBoolean()) { + o = convertToType(getValue(n, outer), boolean.class); + } else if (sType.isCharSequence()) { + o = decodeString(getValue(n, outer)); + } else if (sType.isChar()) { + o = decodeString(getValue(n, outer)).charAt(0); + } else if (sType.isNumber()) { + o = parseNumber(getValue(n, outer).toString(), (Class<? extends Number>)sType.getInnerClass()); + } else if (sType.isMap()) { + Resource r = n.asResource(); + if (! urisVisited.add(r)) + return null; + Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(this)); + o = parseIntoMap(r, m, eType.getKeyType(), eType.getValueType(), pMeta); + } else if (sType.isCollectionOrArray() || sType.isArgs()) { + if (sType.isArray() || sType.isArgs()) + o = new ArrayList(); + else + o = (sType.canCreateNewInstance(outer) ? (Collection<?>)sType.newInstance(outer) : new ObjectList(this)); + Resource r = n.asResource(); + if (! urisVisited.add(r)) + return null; + if (isSeq(r)) { + parseIntoCollection(r.as(Seq.class), (Collection)o, sType, pMeta); + } else if (isBag(r)) { + parseIntoCollection(r.as(Bag.class), (Collection)o, sType, pMeta); + } else if (r.canAs(RDFList.class)) { + parseIntoCollection(r.as(RDFList.class), (Collection)o, sType, pMeta); + } else { + throw new ParseException("Unrecognized node type ''{0}'' for collection", n); + } + if (sType.isArray() || sType.isArgs()) + o = toArray(sType, (Collection)o); + } else if (sType.canCreateNewBean(outer)) { + Resource r = n.asResource(); + if (! urisVisited.add(r)) + return null; + BeanMap<?> bm = newBeanMap(outer, sType.getInnerClass()); + o = parseIntoBeanMap(r, bm).getBean(); + } else if (sType.isUri() && n.isResource()) { + o = sType.newInstanceFromString(outer, decodeString(n.asResource().getURI())); + } else if (sType.canCreateNewInstanceFromString(outer)) { + o = sType.newInstanceFromString(outer, decodeString(getValue(n, outer))); + } else if (sType.canCreateNewInstanceFromNumber(outer)) { + o = sType.newInstanceFromNumber(this, outer, parseNumber(getValue(n, outer).toString(), sType.getNewInstanceFromNumberClass())); + } else if (n.isResource()) { + Resource r = n.asResource(); + Map m = new ObjectMap(this); + parseIntoMap(r, m, sType.getKeyType(), sType.getValueType(), pMeta); + if (m.containsKey(getBeanTypePropertyName(eType))) + o = cast((ObjectMap)m, pMeta, eType); + else + throw new ParseException(loc(), "Class ''{0}'' could not be instantiated. Reason: ''{1}''", sType.getInnerClass().getName(), sType.getNotABeanReason()); + } 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(this, o, eType); + + if (outer != null) + setParent(eType, o, outer); + + return (T)o; + } + + private ObjectMap loc() { + return getLastLocation(); + } + + private boolean isSeq(RDFNode n) { + if (n.isResource()) { + Statement st = n.asResource().getProperty(pRdfType); + if (st != null) + return RDF_SEQ.equals(st.getResource().getURI()); + } + return false; + } + + private boolean isBag(RDFNode n) { + if (n.isResource()) { + Statement st = n.asResource().getProperty(pRdfType); + if (st != null) + return RDF_BAG.equals(st.getResource().getURI()); + } + return false; + } + + private Object getValue(RDFNode n, Object outer) throws Exception { + if (n.isLiteral()) + return n.asLiteral().getValue(); + if (n.isResource()) { + Statement st = n.asResource().getProperty(pValue); + if (st != null) { + n = st.getObject(); + if (n.isLiteral()) + return n.asLiteral().getValue(); + return parseAnything(object(), st.getObject(), outer, null); + } + } + throw new ParseException(loc(), "Unknown value type for node ''{0}''", n); + } + + private <K,V> Map<K,V> parseIntoMap(Resource r, Map<K,V> m, ClassMeta<K> keyType, + ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws Exception { + // Add URI as "uri" to generic maps. + if (r.getURI() != null) { + K uri = convertAttrToType(m, "uri", keyType); + V value = convertAttrToType(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(juneauNs.getUri()))) { + key = decodeString(key); + RDFNode o = st.getObject(); + K key2 = convertAttrToType(m, key, keyType); + V value = parseAnything(valueType, o, m, pMeta); + setName(valueType, value, key); + m.put(key2, value); + } + + } + return m; + } + + private <E> Collection<E> parseIntoCollection(Container c, Collection<E> l, + ClassMeta<?> type, BeanPropertyMeta pMeta) throws Exception { + int argIndex = 0; + for (NodeIterator ni = c.iterator(); ni.hasNext();) { + E e = (E)parseAnything(type.isArgs() ? type.getArg(argIndex++) : type.getElementType(), ni.next(), l, pMeta); + l.add(e); + } + return l; + } + + private <E> Collection<E> parseIntoCollection(RDFList list, Collection<E> l, + ClassMeta<?> type, BeanPropertyMeta pMeta) throws Exception { + int argIndex = 0; + for (ExtendedIterator<RDFNode> ni = list.iterator(); ni.hasNext();) { + E e = (E)parseAnything(type.isArgs() ? type.getArg(argIndex++) : type.getElementType(), ni.next(), l, pMeta); + l.add(e); + } + return l; + } +}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java new file mode 100644 index 0000000..b574186 --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java @@ -0,0 +1,165 @@ +// *************************************************************************************************************************** +// * 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 org.apache.juneau.*; +import org.apache.juneau.serializer.*; + +/** + * Serializes POJOs to RDF. + * + * <h5 class='section'>Configurable properties:</h5> + * + * 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> + * + * 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> + * + * <h5 class='section'>Additional information:</h5> + * + * See <a class="doclink" href="package-summary.html#TOC">RDF Overview</a> for an overview of RDF support in Juneau. + */ +public class RdfSerializer extends WriterSerializer { + + /** Default RDF/XML serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_XML = new Xml(PropertyStore.create()); + + /** Default Abbreviated RDF/XML serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_XMLABBREV = new XmlAbbrev(PropertyStore.create()); + + /** Default Turtle serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_TURTLE = new Turtle(PropertyStore.create()); + + /** Default N-Triple serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_NTRIPLE = new NTriple(PropertyStore.create()); + + /** Default N3 serializer, all default settings.*/ + public static final RdfSerializer DEFAULT_N3 = new N3(PropertyStore.create()); + + + /** Produces RDF/XML output */ + public static class Xml extends RdfSerializer { + + /** + * Constructor. + * + * @param propertyStore The property store containing all the settings for this object. + */ + public Xml(PropertyStore propertyStore) { + super(propertyStore.copy().append(RDF_language, LANG_RDF_XML), "text/xml+rdf"); + } + } + + /** Produces Abbreviated RDF/XML output */ + public static class XmlAbbrev extends RdfSerializer { + + /** + * Constructor. + * + * @param propertyStore The property store containing all the settings for this object. + */ + public XmlAbbrev(PropertyStore propertyStore) { + super(propertyStore.copy().append(RDF_language, LANG_RDF_XML_ABBREV), "text/xml+rdf", "text/xml+rdf+abbrev"); + } + } + + /** Produces N-Triple output */ + public static class NTriple extends RdfSerializer { + + /** + * Constructor. + * + * @param propertyStore The property store containing all the settings for this object. + */ + public NTriple(PropertyStore propertyStore) { + super(propertyStore.copy().append(RDF_language, LANG_NTRIPLE), "text/n-triple"); + } + } + + /** Produces Turtle output */ + public static class Turtle extends RdfSerializer { + + /** + * Constructor. + * + * @param propertyStore The property store containing all the settings for this object. + */ + public Turtle(PropertyStore propertyStore) { + super(propertyStore.copy().append(RDF_language, LANG_TURTLE), "text/turtle"); + } + } + + /** Produces N3 output */ + public static class N3 extends RdfSerializer { + + /** + * Constructor. + * + * @param propertyStore The property store containing all the settings for this object. + */ + public N3(PropertyStore propertyStore) { + super(propertyStore.copy().append(RDF_language, LANG_N3), "text/n3"); + } + } + + + private final RdfSerializerContext ctx; + + /** + * Constructor. + * + * @param propertyStore + * The property store containing all the settings for this object. + * @param produces + * The media type that this serializer produces. + * @param accept + * The accept media types that the serializer can handle. + * <p> + * Can contain meta-characters per the <code>media-type</code> specification of + * <a class="doclink" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">RFC2616/14.1</a> + * <p> + * If empty, then assumes the only media type supported is <code>produces</code>. + * <p> + * For example, if this serializer produces <js>"application/json"</js> but should handle media types of + * <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be: + * <br><code><jk>super</jk>(propertyStore, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);</code> + * <br>...or... + * <br><code><jk>super</jk>(propertyStore, <js>"application/json"</js>, <js>"*​/json"</js>);</code> + */ + public RdfSerializer(PropertyStore propertyStore, String produces, String...accept) { + super(propertyStore, produces, accept); + this.ctx = createContext(RdfSerializerContext.class); + } + + @Override /* CoreObject */ + public RdfSerializerBuilder builder() { + return new RdfSerializerBuilder(propertyStore); + } + + @Override /* Serializer */ + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new RdfSerializerSession(ctx, args); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerBuilder.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerBuilder.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerBuilder.java new file mode 100644 index 0000000..59b15c5 --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerBuilder.java @@ -0,0 +1,978 @@ +// *************************************************************************************************************************** +// * 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.RdfCommonContext.*; +import static org.apache.juneau.jena.RdfSerializerContext.*; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.http.*; +import org.apache.juneau.jena.annotation.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.xml.*; +import org.apache.juneau.xml.annotation.*; + +/** + * Builder class for building instances of RDF serializers. + */ +public class RdfSerializerBuilder extends SerializerBuilder { + + /** + * Constructor, default settings. + */ + public RdfSerializerBuilder() { + super(); + } + + /** + * Constructor. + * + * @param propertyStore The initial configuration settings for this builder. + */ + public RdfSerializerBuilder(PropertyStore propertyStore) { + super(propertyStore); + } + + @Override /* CoreObjectBuilder */ + public RdfSerializer build() { + return new RdfSerializer(propertyStore, "text/xml+rdf"); + } + + + //-------------------------------------------------------------------------------- + // Properties + //-------------------------------------------------------------------------------- + + /** + * <b>Configuration property:</b> RDF language. + * + * <ul> + * <li><b>Name:</b> <js>"Rdf.language"</js> + * <li><b>Data type:</b> <code>String</code> + * <li><b>Default:</b> <js>"RDF/XML-ABBREV"</js> + * </ul> + * + * <p> + * Can be any of the following: + * <ul class='spaced-list'> + * <li> + * <js>"RDF/XML"</js> + * <li> + * <js>"RDF/XML-ABBREV"</js> + * <li> + * <js>"N-TRIPLE"</js> + * <li> + * <js>"N3"</js> - General name for the N3 writer. + * Will make a decision on exactly which writer to use (pretty writer, plain writer or simple writer) when + * created. + * Default is the pretty writer but can be overridden with system property + * <code>com.hp.hpl.jena.n3.N3JenaWriter.writer</code>. + * <li> + * <js>"N3-PP"</js> - Name of the N3 pretty writer. + * The pretty writer uses a frame-like layout, with prefixing, clustering like properties and embedding + * one-referenced bNodes. + * <li> + * <js>"N3-PLAIN"</js> - Name of the N3 plain writer. + * The plain writer writes records by subject. + * <li> + * <js>"N3-TRIPLES"</js> - Name of the N3 triples writer. + * This writer writes one line per statement, like N-Triples, but does N3-style prefixing. + * <li> + * <js>"TURTLE"</js> - Turtle writer. + * http://www.dajobe.org/2004/01/turtle/ + * </ul> + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_language</jsf>, value)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see RdfCommonContext#RDF_language + */ + public RdfSerializerBuilder language(String value) { + return property(RDF_language, value); + } + + /** + * Shortcut for calling <code>language(<jsf>LANG_RDF_XML</jsf>)</code> + * + * @return This object (for method chaining). + */ + public RdfSerializerBuilder xml() { + return language(Constants.LANG_RDF_XML); + } + + /** + * Shortcut for calling <code>language(<jsf>LANG_RDF_XML_ABBREV</jsf>)</code> + * + * @return This object (for method chaining). + */ + public RdfSerializerBuilder xmlabbrev() { + return language(Constants.LANG_RDF_XML_ABBREV); + } + + /** + * Shortcut for calling <code>language(<jsf>LANG_NTRIPLE</jsf>)</code> + * + * @return This object (for method chaining). + */ + public RdfSerializerBuilder ntriple() { + return language(Constants.LANG_NTRIPLE); + } + + /** + * Shortcut for calling <code>language(<jsf>LANG_N3</jsf>)</code> + * + * @return This object (for method chaining). + */ + public RdfSerializerBuilder n3() { + return language(Constants.LANG_N3); + } + + /** + * Shortcut for calling <code>language(<jsf>LANG_TURTLE</jsf>)</code> + * + * @return This object (for method chaining). + */ + public RdfSerializerBuilder turtle() { + return language(Constants.LANG_TURTLE); + } + + /** + * <b>Configuration property:</b> XML namespace for Juneau properties. + * + * <ul> + * <li><b>Name:</b> <js>"Rdf.juneauNs"</js> + * <li><b>Data type:</b> {@link Namespace} + * <li><b>Default:</b> <code>{j:<js>'http://www.apache.org/juneau/'</js>}</code> + * </ul> + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_juneauNs</jsf>, value)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see RdfSerializerContext#RDF_juneauNs + */ + public RdfSerializerBuilder juneauNs(Namespace value) { + return property(RDF_juneauNs, value); + } + + /** + * <b>Configuration property:</b> Default XML namespace for bean properties. + * + * <ul> + * <li><b>Name:</b> <js>"Rdf.juneauBpNs"</js> + * <li><b>Data type:</b> {@link Namespace} + * <li><b>Default:</b> <code>{j:<js>'http://www.apache.org/juneaubp/'</js>}</code> + * </ul> + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_juneauBpNs</jsf>, value)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see RdfSerializerContext#RDF_juneauBpNs + */ + public RdfSerializerBuilder juneauBpNs(Namespace value) { + return property(RDF_juneauBpNs, value); + } + + /** + * <b>Configuration property:</b> Reuse XML namespaces when RDF namespaces not specified. + * + * <ul> + * <li><b>Name:</b> <js>"Rdf.useXmlNamespaces"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>true</jk> + * </ul> + * + * <p> + * When specified, namespaces defined using {@link XmlNs} and {@link Xml} will be inherited by the RDF serializers. + * Otherwise, namespaces will be defined using {@link RdfNs} and {@link Rdf}. + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_useXmlNamespaces</jsf>, value)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see SerializerContext#SERIALIZER_sortMaps + */ + public RdfSerializerBuilder useXmlNamespaces(boolean value) { + return property(RDF_useXmlNamespaces, value); + } + + /** + * <b>Configuration property:</b> Add XSI data types to non-<code>String</code> literals. + * + * <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> + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_addLiteralTypes</jsf>, value)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see RdfSerializerContext#RDF_addLiteralTypes + */ + public RdfSerializerBuilder addLiteralTypes(boolean value) { + return property(RDF_addLiteralTypes, value); + } + + /** + * <b>Configuration property:</b> Add RDF root identifier property to root node. + * + * <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. + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_addRootProperty</jsf>, value)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see RdfSerializerContext#RDF_addRootProperty + */ + public RdfSerializerBuilder addRootProperty(boolean value) { + return property(RDF_addRootProperty, value); + } + + /** + * <b>Configuration property:</b> Auto-detect namespace usage. + * + * <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. + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_autoDetectNamespaces</jsf>, value)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see RdfSerializerContext#RDF_autoDetectNamespaces + */ + public RdfSerializerBuilder autoDetectNamespaces(boolean value) { + return property(RDF_autoDetectNamespaces, value); + } + + /** + * <b>Configuration property:</b> Default namespaces. + * + * <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. + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_namespaces</jsf>, values)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param values The new value for this property. + * @return This object (for method chaining). + * @see RdfSerializerContext#RDF_namespaces + */ + public RdfSerializerBuilder namespaces(Namespace...values) { + return property(RDF_namespaces, values); + } + + /** + * <b>Configuration property:</b> RDF format for representing collections and arrays. + * + * <ul> + * <li><b>Name:</b> <js>"Rdf.collectionFormat"</js> + * <li><b>Data type:</b> <code>RdfCollectionFormat</code> + * <li><b>Default:</b> <js>"DEFAULT"</js> + * </ul> + * + * <p> + * Possible values: + * <ul class='spaced-list'> + * <li> + * <js>"DEFAULT"</js> - Default format. The default is an RDF Sequence container. + * <li> + * <js>"SEQ"</js> - RDF Sequence container. + * <li> + * <js>"BAG"</js> - RDF Bag container. + * <li> + * <js>"LIST"</js> - RDF List container. + * <li> + * <js>"MULTI_VALUED"</js> - Multi-valued properties. + * </ul> + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>If you use <js>"BAG"</js> or <js>"MULTI_VALUED"</js>, the order of the elements in the collection will get + * lost. + * </ul> + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_collectionFormat</jsf>, value)</code>. + * <li>This introduces a slight performance penalty. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see RdfCommonContext#RDF_collectionFormat + */ + public RdfSerializerBuilder collectionFormat(RdfCollectionFormat value) { + return property(RDF_collectionFormat, value); + } + + /** + * <b>Configuration property:</b> Collections should be serialized and parsed as loose collections. + * + * <ul> + * <li><b>Name:</b> <js>"Rdf.looseCollections"</js> + * <li><b>Data type:</b> <code>Boolean</code> + * <li><b>Default:</b> <jk>false</jk> + * </ul> + * + * <p> + * When specified, collections of resources are handled as loose collections of resources in RDF instead of + * resources that are children of an RDF collection (e.g. Sequence, Bag). + * + * <p> + * Note that this setting is specialized for RDF syntax, and is incompatible with the concept of + * losslessly representing POJO models, since the tree structure of these POJO models are lost + * when serialized as loose collections. + * + * <p> + * This setting is typically only useful if the beans being parsed into do not have a bean property + * annotated with {@link Rdf#beanUri @Rdf(beanUri=true)}. + * + * <h5 class='section'>Example:</h5> + * <p class='bcode'> + * WriterSerializer s = <jk>new</jk> RdfSerializerBuilder().xmlabbrev().looseCollections(<jk>true</jk>).build(); + * ReaderParser p = <jk>new</jk> RdfParserBuilder().xml().looseCollections(<jk>true</jk>).build(); + * + * List<MyBean> l = createListOfMyBeans(); + * + * <jc>// Serialize to RDF/XML as loose resources</jc> + * String rdfXml = s.serialize(l); + * + * <jc>// Parse back into a Java collection</jc> + * l = p.parse(rdfXml, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>); + * + * MyBean[] b = createArrayOfMyBeans(); + * + * <jc>// Serialize to RDF/XML as loose resources</jc> + * String rdfXml = s.serialize(b); + * + * <jc>// Parse back into a bean array</jc> + * b = p.parse(rdfXml, MyBean[].<jk>class</jk>); + * </p> + * + * <h5 class='section'>Notes:</h5> + * <ul> + * <li>This is equivalent to calling <code>property(<jsf>RDF_looseCollections</jsf>, value)</code>. + * </ul> + * + * @param value The new value for this property. + * @return This object (for method chaining). + * @see RdfCommonContext#RDF_looseCollections + */ + public RdfSerializerBuilder looseCollections(boolean value) { + return property(RDF_looseCollections, value); + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder maxDepth(int value) { + super.maxDepth(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder initialDepth(int value) { + super.initialDepth(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder detectRecursions(boolean value) { + super.detectRecursions(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder ignoreRecursions(boolean value) { + super.ignoreRecursions(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder useWhitespace(boolean value) { + super.useWhitespace(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder ws() { + super.ws(); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder addBeanTypeProperties(boolean value) { + super.addBeanTypeProperties(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder quoteChar(char value) { + super.quoteChar(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder sq() { + super.sq(); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder trimNullProperties(boolean value) { + super.trimNullProperties(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder trimEmptyCollections(boolean value) { + super.trimEmptyCollections(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder trimEmptyMaps(boolean value) { + super.trimEmptyMaps(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder trimStrings(boolean value) { + super.trimStrings(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder uriContext(UriContext value) { + super.uriContext(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder uriResolution(UriResolution value) { + super.uriResolution(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder uriRelativity(UriRelativity value) { + super.uriRelativity(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder sortCollections(boolean value) { + super.sortCollections(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder sortMaps(boolean value) { + super.sortMaps(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder abridged(boolean value) { + super.abridged(value); + return this; + } + + @Override /* SerializerBuilder */ + public RdfSerializerBuilder listener(Class<? extends SerializerListener> value) { + super.listener(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beansRequireDefaultConstructor(boolean value) { + super.beansRequireDefaultConstructor(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beansRequireSerializable(boolean value) { + super.beansRequireSerializable(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beansRequireSettersForGetters(boolean value) { + super.beansRequireSettersForGetters(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beansRequireSomeProperties(boolean value) { + super.beansRequireSomeProperties(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanMapPutReturnsOldValue(boolean value) { + super.beanMapPutReturnsOldValue(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanConstructorVisibility(Visibility value) { + super.beanConstructorVisibility(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanClassVisibility(Visibility value) { + super.beanClassVisibility(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanFieldVisibility(Visibility value) { + super.beanFieldVisibility(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder methodVisibility(Visibility value) { + super.methodVisibility(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder useJavaBeanIntrospector(boolean value) { + super.useJavaBeanIntrospector(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder useInterfaceProxies(boolean value) { + super.useInterfaceProxies(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder ignoreUnknownBeanProperties(boolean value) { + super.ignoreUnknownBeanProperties(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder ignoreUnknownNullBeanProperties(boolean value) { + super.ignoreUnknownNullBeanProperties(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder ignorePropertiesWithoutSetters(boolean value) { + super.ignorePropertiesWithoutSetters(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder ignoreInvocationExceptionsOnGetters(boolean value) { + super.ignoreInvocationExceptionsOnGetters(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder ignoreInvocationExceptionsOnSetters(boolean value) { + super.ignoreInvocationExceptionsOnSetters(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder sortProperties(boolean value) { + super.sortProperties(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder notBeanPackages(String...values) { + super.notBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder notBeanPackages(Collection<String> values) { + super.notBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setNotBeanPackages(String...values) { + super.setNotBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setNotBeanPackages(Collection<String> values) { + super.setNotBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeNotBeanPackages(String...values) { + super.removeNotBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeNotBeanPackages(Collection<String> values) { + super.removeNotBeanPackages(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder notBeanClasses(Class<?>...values) { + super.notBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder notBeanClasses(Collection<Class<?>> values) { + super.notBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setNotBeanClasses(Class<?>...values) { + super.setNotBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setNotBeanClasses(Collection<Class<?>> values) { + super.setNotBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeNotBeanClasses(Class<?>...values) { + super.removeNotBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeNotBeanClasses(Collection<Class<?>> values) { + super.removeNotBeanClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanFilters(Class<?>...values) { + super.beanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanFilters(Collection<Class<?>> values) { + super.beanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setBeanFilters(Class<?>...values) { + super.setBeanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setBeanFilters(Collection<Class<?>> values) { + super.setBeanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeBeanFilters(Class<?>...values) { + super.removeBeanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeBeanFilters(Collection<Class<?>> values) { + super.removeBeanFilters(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder pojoSwaps(Class<?>...values) { + super.pojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder pojoSwaps(Collection<Class<?>> values) { + super.pojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setPojoSwaps(Class<?>...values) { + super.setPojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setPojoSwaps(Collection<Class<?>> values) { + super.setPojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removePojoSwaps(Class<?>...values) { + super.removePojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removePojoSwaps(Collection<Class<?>> values) { + super.removePojoSwaps(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder implClasses(Map<Class<?>,Class<?>> values) { + super.implClasses(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public <T> RdfSerializerBuilder implClass(Class<T> interfaceClass, Class<? extends T> implClass) { + super.implClass(interfaceClass, implClass); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder includeProperties(Map<String,String> values) { + super.includeProperties(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder includeProperties(String beanClassName, String properties) { + super.includeProperties(beanClassName, properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder includeProperties(Class<?> beanClass, String properties) { + super.includeProperties(beanClass, properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder excludeProperties(Map<String,String> values) { + super.excludeProperties(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder excludeProperties(String beanClassName, String properties) { + super.excludeProperties(beanClassName, properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder excludeProperties(Class<?> beanClass, String properties) { + super.excludeProperties(beanClass, properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanDictionary(Class<?>...values) { + super.beanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanDictionary(Collection<Class<?>> values) { + super.beanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setBeanDictionary(Class<?>...values) { + super.setBeanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder setBeanDictionary(Collection<Class<?>> values) { + super.setBeanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeFromBeanDictionary(Class<?>...values) { + super.removeFromBeanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeFromBeanDictionary(Collection<Class<?>> values) { + super.removeFromBeanDictionary(values); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder beanTypePropertyName(String value) { + super.beanTypePropertyName(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder defaultParser(Class<?> value) { + super.defaultParser(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder locale(Locale value) { + super.locale(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder timeZone(TimeZone value) { + super.timeZone(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder mediaType(MediaType value) { + super.mediaType(value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder debug() { + super.debug(); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder property(String name, Object value) { + super.property(name, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder properties(Map<String,Object> properties) { + super.properties(properties); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder addToProperty(String name, Object value) { + super.addToProperty(name, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder putToProperty(String name, Object key, Object value) { + super.putToProperty(name, key, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder putToProperty(String name, Object value) { + super.putToProperty(name, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder removeFromProperty(String name, Object value) { + super.removeFromProperty(name, value); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder classLoader(ClassLoader classLoader) { + super.classLoader(classLoader); + return this; + } + + @Override /* CoreObjectBuilder */ + public RdfSerializerBuilder apply(PropertyStore copyFrom) { + super.apply(copyFrom); + return this; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerContext.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerContext.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerContext.java new file mode 100644 index 0000000..2d5d6aa --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerContext.java @@ -0,0 +1,197 @@ +// *************************************************************************************************************************** +// * 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 PropertyStore#setProperty(String, Object)} on the property store + * passed into the constructor. + * + * <p> + * See {@link PropertyStore} for more information about context properties. + * + * <h6 class='topic' id='ConfigProperties'>Configurable properties inherited by the RDF serializers</h6> + * <ul class='doctree'> + * <li class='jc'> + * <a class="doclink" href="../BeanContext.html#ConfigProperties">BeanContext</a> + * - Properties associated with handling beans on serializers and parsers. + * <ul> + * <li class='jc'> + * <a class="doclink" href="../serializer/SerializerContext.html#ConfigProperties">SerializerContext</a> + * - Configurable properties common to all serializers. + * <ul> + * <li class='jc'> + * <a class="doclink" href="RdfCommonContext.html#ConfigProperties">RdfCommonContext</a> + * - Configurable properties common to the RDF serializers and parsers. + * </ul> + * </li> + * </ul> + * </li> + * </ul> + */ +public final class RdfSerializerContext extends SerializerContext implements RdfCommonContext { + + /** + * <b>Configuration property:</b> Add XSI data types to non-<code>String</code> literals. + * + * <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. + * + * <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. + * + * <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. + * + * <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"; + + /** + * <b>Configuration property:</b> Add <js>"_type"</js> properties when needed. + * + * <ul> + * <li><b>Name:</b> <js>"RdfSerializer.addBeanTypeProperties"</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>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred + * through reflection. + * This is used to recreate the correct objects during parsing if the object types cannot be inferred. + * For example, when serializing a {@code Map<String,Object>} field, where the bean class cannot be determined + * from the value type. + * + * <p> + * When present, this value overrides the {@link SerializerContext#SERIALIZER_addBeanTypeProperties} setting and is + * provided to customize the behavior of specific serializers in a {@link SerializerGroup}. + */ + public static final String RDF_addBeanTypeProperties = "RdfSerializer.addBeanTypeProperties"; + + + final boolean + addLiteralTypes, + addRootProperty, + useXmlNamespaces, + looseCollections, + autoDetectNamespaces, + addBeanTypeProperties; + 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 PropertyStore#getContext(Class)}. + * + * @param ps The property store that created this context. + */ + public RdfSerializerContext(PropertyStore ps) { + super(ps); + addLiteralTypes = ps.getProperty(RDF_addLiteralTypes, boolean.class, false); + addRootProperty = ps.getProperty(RDF_addRootProperty, boolean.class, false); + useXmlNamespaces = ps.getProperty(RDF_useXmlNamespaces, boolean.class, true); + looseCollections = ps.getProperty(RDF_looseCollections, boolean.class, false); + autoDetectNamespaces = ps.getProperty(RDF_autoDetectNamespaces, boolean.class, true); + rdfLanguage = ps.getProperty(RDF_language, String.class, "RDF/XML-ABBREV"); + juneauNs = ps.getProperty(RDF_juneauNs, Namespace.class, new Namespace("j", "http://www.apache.org/juneau/")); + juneauBpNs = ps.getProperty(RDF_juneauBpNs, Namespace.class, new Namespace("jp", "http://www.apache.org/juneaubp/")); + collectionFormat = ps.getProperty(RDF_collectionFormat, RdfCollectionFormat.class, RdfCollectionFormat.DEFAULT); + namespaces = ps.getProperty(RDF_namespaces, Namespace[].class, new Namespace[0]); + addBeanTypeProperties = ps.getProperty(RDF_addBeanTypeProperties, boolean.class, ps.getProperty(SERIALIZER_addBeanTypeProperties, boolean.class, true)); + } + + @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) + .append("addBeanTypeProperties", addBeanTypeProperties) + ); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java new file mode 100644 index 0000000..0f66237 --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java @@ -0,0 +1,414 @@ +// *************************************************************************************************************************** +// * 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.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.internal.*; +import org.apache.juneau.msgpack.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.transform.*; +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 typically discarded after one-time use although it can be reused within the same thread. + */ +@SuppressWarnings({ "rawtypes", "unchecked" }) +public final class RdfSerializerSession extends WriterSerializerSession { + + private final String rdfLanguage; + private final Namespace juneauNs, juneauBpNs; + private final boolean + addLiteralTypes, + addRootProperty, + useXmlNamespaces, + looseCollections, + autoDetectNamespaces, + addBeanTypeProperties; + private final Property pRoot, pValue; + 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 args + * Runtime arguments. + * These specify session-level information such as locale and URI context. + * It also include session-level properties that override the properties defined on the bean and + * serializer contexts. + */ + protected RdfSerializerSession(RdfSerializerContext ctx, SerializerSessionArgs args) { + super(ctx, args); + ObjectMap jenaSettings = new ObjectMap(); + jenaSettings.put("rdfXml.tab", isUseWhitespace() ? 2 : 0); + jenaSettings.put("rdfXml.attributeQuoteChar", Character.toString(getQuoteChar())); + jenaSettings.putAll(ctx.jenaSettings); + ObjectMap p = getProperties(); + if (p.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; + addBeanTypeProperties = ctx.addBeanTypeProperties; + } else { + this.rdfLanguage = p.getString(RDF_language, ctx.rdfLanguage); + this.juneauNs = (p.containsKey(RDF_juneauNs) ? NamespaceFactory.parseNamespace(p.get(RDF_juneauNs)) : ctx.juneauNs); + this.juneauBpNs = (p.containsKey(RDF_juneauBpNs) ? NamespaceFactory.parseNamespace(p.get(RDF_juneauBpNs)) : ctx.juneauBpNs); + this.addLiteralTypes = p.getBoolean(RDF_addLiteralTypes, ctx.addLiteralTypes); + this.addRootProperty = p.getBoolean(RDF_addRootProperty, ctx.addRootProperty); + for (Map.Entry<String,Object> e : p.entrySet()) { + String key = e.getKey(); + if (key.startsWith("Rdf.jena.")) + jenaSettings.put(key.substring(9), e.getValue()); + } + this.collectionFormat = RdfCollectionFormat.valueOf(p.getString(RDF_collectionFormat, "DEFAULT")); + this.looseCollections = p.getBoolean(RDF_looseCollections, ctx.looseCollections); + this.useXmlNamespaces = p.getBoolean(RDF_useXmlNamespaces, ctx.useXmlNamespaces); + this.autoDetectNamespaces = p.getBoolean(RDF_autoDetectNamespaces, ctx.autoDetectNamespaces); + this.namespaces = p.getWithDefault(RDF_namespaces, ctx.namespaces, Namespace[].class); + addBeanTypeProperties = p.getBoolean(RDF_addBeanTypeProperties, ctx.addBeanTypeProperties); + } + 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); + writer = model.getWriter(rdfLanguage); + + // Only apply properties with this prefix! + String propPrefix = RdfCommonContext.LANG_PROP_MAP.get(rdfLanguage); + if (propPrefix == null) + throw new FormattedRuntimeException("Unknown RDF language encountered: ''{0}''", 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. + */ + private void addModelPrefix(Namespace ns) { + model.setNsPrefix(ns.getName(), ns.getUri()); + } + + /** + * Returns the {@link MsgPackSerializerContext#MSGPACK_addBeanTypeProperties} setting value for this session. + * + * @return The {@link MsgPackSerializerContext#MSGPACK_addBeanTypeProperties} setting value for this session. + */ + @Override /* SerializerSession */ + public final boolean isAddBeanTypeProperties() { + return addBeanTypeProperties; + } + + /* + * XML-encodes the specified string using the {@link XmlUtils#escapeText(Object)} method. + */ + private String encodeTextInvalidChars(Object o) { + if (o == null) + return null; + String s = toString(o); + return XmlUtils.escapeText(s); + } + + /* + * XML-encoded the specified element name using the {@link XmlUtils#encodeElementName(Object)} method. + */ + private String encodeElementName(Object o) { + return XmlUtils.encodeElementName(toString(o)); + } + + @Override /* Serializer */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + + Resource r = null; + + ClassMeta<?> cm = getClassMetaForObject(o); + if (looseCollections && cm != null && cm.isCollectionOrArray()) { + Collection c = sort(cm.isCollection() ? (Collection)o : toList(cm.getInnerClass(), o)); + for (Object o2 : c) + serializeAnything(o2, false, object(), "root", null, null); + } else { + RDFNode n = serializeAnything(o, false, getExpectedRootType(o), "root", null, null); + if (n.isLiteral()) { + r = model.createResource(); + r.addProperty(pValue, n); + } else { + r = n.asResource(); + } + + if (addRootProperty) + r.addProperty(pRoot, "true"); + } + + writer.write(model, out.getWriter(), "http://unknown/"); + } + + private RDFNode serializeAnything(Object o, boolean isURI, ClassMeta<?> eType, + String attrName, BeanPropertyMeta bpm, Resource parentResource) throws Exception { + Model m = model; + + ClassMeta<?> aType = null; // The actual type + ClassMeta<?> wType = null; // The wrapped type + ClassMeta<?> sType = object(); // The serialized type + + aType = 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(this, o); + + // If the getSwapClass() method returns Object, we need to figure out + // the actual type now. + if (sType.isObject()) + sType = getClassMetaForObject(o); + } + } else { + sType = eType.getSerializedClassMeta(); + } + + String typeName = getBeanTypeName(eType, aType, bpm); + + RDFNode n = null; + + if (o == null || sType.isChar() && ((Character)o).charValue() == 0) { + if (bpm != null) { + if (! isTrimNulls()) { + n = m.createResource(RDF_NIL); + } + } else { + n = m.createResource(RDF_NIL); + } + + } else if (sType.isUri() || isURI) { + // Note that RDF URIs must be absolute to be valid! + String uri = getUri(o, null); + if (StringUtils.isAbsoluteUri(uri)) + n = m.createResource(uri); + else + n = m.createLiteral(encodeTextInvalidChars(uri)); + + } else if (sType.isCharSequence() || sType.isChar()) { + n = m.createLiteral(encodeTextInvalidChars(o)); + + } else if (sType.isNumber() || sType.isBoolean()) { + if (! addLiteralTypes) + 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, null); + String uri2 = getUri(uri, null); + n = m.createResource(uri2); + serializeBeanMap(bm, (Resource)n, typeName); + } else { + Map m2 = (Map)o; + n = m.createResource(); + serializeMap(m2, (Resource)n, sType); + } + + } else if (sType.isBean()) { + BeanMap bm = toBeanMap(o); + Object uri = null; + RdfBeanMeta rbm = (RdfBeanMeta)bm.getMeta().getExtendedMeta(RdfBeanMeta.class); + if (rbm.hasBeanUri()) + uri = rbm.getBeanUriProperty().get(bm, null); + String uri2 = getUri(uri, null); + n = m.createResource(uri2); + serializeBeanMap(bm, (Resource)n, typeName); + + } else if (sType.isCollectionOrArray() || (wType != null && wType.isCollection())) { + Collection c = sort(sType.isCollection() ? (Collection)o : toList(sType.getInnerClass(), o)); + RdfCollectionFormat f = collectionFormat; + 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(c, eType, m.createBag()); break; + case LIST: n = serializeToList(c, eType); break; + case MULTI_VALUED: serializeToMultiProperties(c, eType, bpm, attrName, parentResource); break; + default: n = serializeToContainer(c, eType, m.createSeq()); + } + + } else if (sType.isReader() || sType.isInputStream()) { + n = m.createLiteral(encodeTextInvalidChars(IOUtils.read(o))); + + } else { + n = m.createLiteral(encodeTextInvalidChars(toString(o))); + } + + pop(); + + return n; + } + + private String getUri(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; + return getUriResolver().resolve(s); + } + + private void serializeMap(Map m, Resource r, ClassMeta<?> type) throws Exception { + + m = 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 = generalize(me.getKey(), keyType); + + Namespace ns = juneauBpNs; + Property p = model.createProperty(ns.getUri(), encodeElementName(toString(key))); + RDFNode n = serializeAnything(value, false, valueType, key == null ? null : toString(key), null, r); + if (n != null) + r.addProperty(p, n); + } + } + + private void serializeBeanMap(BeanMap<?> m, Resource r, String typeName) throws Exception { + List<BeanPropertyValue> l = m.getValues(isTrimNulls(), typeName != null ? createBeanTypeNameProperty(m, typeName) : null); + 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) + onBeanGetterException(pMeta, t); + + if (canIgnoreValue(cMeta, key, value)) + continue; + + BeanPropertyMeta bpm = bpv.getMeta(); + Namespace ns = bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getNamespace(); + if (ns == null && useXmlNamespaces) + ns = bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace(); + if (ns == null) + ns = juneauBpNs; + else if (autoDetectNamespaces) + addModelPrefix(ns); + + Property p = model.createProperty(ns.getUri(), encodeElementName(key)); + RDFNode n = serializeAnything(value, pMeta.isUri(), cMeta, key, pMeta, r); + if (n != null) + r.addProperty(p, n); + } + } + + + private Container serializeToContainer(Collection c, ClassMeta<?> type, Container list) throws Exception { + + ClassMeta<?> elementType = type.getElementType(); + for (Object e : c) { + RDFNode n = serializeAnything(e, false, elementType, null, null, null); + list = list.add(n); + } + return list; + } + + private RDFList serializeToList(Collection c, ClassMeta<?> type) throws Exception { + ClassMeta<?> elementType = type.getElementType(); + List<RDFNode> l = new ArrayList<RDFNode>(c.size()); + for (Object e : c) { + l.add(serializeAnything(e, false, elementType, null, null, null)); + } + return model.createList(l.iterator()); + } + + private void serializeToMultiProperties(Collection c, ClassMeta<?> sType, + BeanPropertyMeta bpm, String attrName, Resource parentResource) throws Exception { + ClassMeta<?> elementType = sType.getElementType(); + for (Object e : c) { + Namespace ns = null; + if (bpm != null) { + ns = bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getNamespace(); + if (ns == null && useXmlNamespaces) + ns = bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace(); + } + if (ns == null) + ns = juneauBpNs; + else if (autoDetectNamespaces) + addModelPrefix(ns); + RDFNode n2 = serializeAnything(e, false, elementType, null, null, null); + Property p = model.createProperty(ns.getUri(), encodeElementName(attrName)); + parentResource.addProperty(p, n2); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfUtils.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfUtils.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfUtils.java new file mode 100644 index 0000000..0432efb --- /dev/null +++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfUtils.java @@ -0,0 +1,92 @@ +// *************************************************************************************************************************** +// * 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. + * + * <p> + * 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; + } +}
