You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2011/03/26 12:07:17 UTC
svn commit: r1085690 [3/11] - in /incubator/isis/trunk: ./ applib/ core/
core/commons/
core/commons/src/main/java/org/apache/isis/core/commons/authentication/
core/commons/src/site/ core/metamodel/
core/metamodel/src/main/java/org/apache/isis/core/meta...
Added: incubator/isis/trunk/core/runtime/src/main/java/org/apache/isis/core/runtime/snapshot/XmlSnapshot.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/core/runtime/src/main/java/org/apache/isis/core/runtime/snapshot/XmlSnapshot.java?rev=1085690&view=auto
==============================================================================
--- incubator/isis/trunk/core/runtime/src/main/java/org/apache/isis/core/runtime/snapshot/XmlSnapshot.java (added)
+++ incubator/isis/trunk/core/runtime/src/main/java/org/apache/isis/core/runtime/snapshot/XmlSnapshot.java Sat Mar 26 11:07:04 2011
@@ -0,0 +1,741 @@
+/*
+ * 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.isis.core.runtime.snapshot;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.isis.applib.snapshot.SnapshottableWithInclusions;
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
+import org.apache.isis.core.metamodel.adapter.oid.stringable.directly.DirectlyStringableOid;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
+import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
+import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
+import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.ObjectSpecificationException;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+/**
+ * Traverses object graph from specified root, so that an XML representation of the graph can be returned.
+ *
+ * <p>
+ * Initially designed to allow snapshots to be easily created.
+ *
+ * <p>
+ * Typical use:
+ * <pre>
+ * XmlSnapshot snapshot = new XmlSnapshot(customer); // where customer is a reference to an ObjectAdapter
+ * Element customerAsXml = snapshot.toXml(); // returns customer's fields, titles of simple references, number of items in collections
+ * snapshot.include("placeOfBirth"); // navigates to another object represented by simple reference "placeOfBirth"
+ * snapshot.include("orders/product"); // navigates to all <tt>Order</tt>s of <tt>Customer</tt>, and from them for their <tt>Product</tt>s
+ * </pre>
+ */
+public class XmlSnapshot {
+
+ private static final Logger LOG = Logger.getLogger(XmlSnapshot.class);
+
+ private final IsisMetaModel isisMetaModel;
+
+ private final Place rootPlace;
+
+ private final XmlSchema schema;
+
+ /**
+ * the suggested location for the schema (xsi:schemaLocation attribute)
+ */
+ private String schemaLocationFileName;
+ private boolean topLevelElementWritten = false;
+
+ private final Document xmlDocument;
+
+ /**
+ * root element of {@link #xmlDocument}
+ */
+ private Element xmlElement;
+ private final Document xsdDocument;
+ /**
+ * root element of {@link #xsdDocument}
+ */
+ private final Element xsdElement;
+
+ private final XsMetaModel xsMeta;
+
+ /**
+ * Start a snapshot at the root object, using own namespace manager.
+ */
+ public XmlSnapshot(final ObjectAdapter rootAdapter) {
+ this(rootAdapter, new XmlSchema());
+ }
+
+ /**
+ * Start a snapshot at the root object, using supplied namespace manager.
+ */
+ public XmlSnapshot(final ObjectAdapter rootAdapter, final XmlSchema schema) {
+
+ LOG.debug(".ctor(" + log("rootObj", rootAdapter) + andlog("schema", schema) + andlog("addOids", "" + true) + ")");
+
+ this.isisMetaModel = new IsisMetaModel();
+ this.xsMeta = new XsMetaModel();
+
+ this.schema = schema;
+
+ final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ DocumentBuilder db;
+ try {
+ db = dbf.newDocumentBuilder();
+ this.xmlDocument = db.newDocument();
+ this.xsdDocument = db.newDocument();
+
+ xsdElement = xsMeta.createXsSchemaElement(xsdDocument);
+
+ this.rootPlace = appendXml(rootAdapter);
+
+ } catch (final ParserConfigurationException e) {
+ LOG.error("unable to build snapshot", e);
+ throw new IsisException(e);
+ }
+
+ for(String path: getPathsFor(rootAdapter.getObject())) {
+ include(path);
+ }
+
+ }
+
+ private List<String> getPathsFor(Object object) {
+ if (!(object instanceof SnapshottableWithInclusions)) {
+ return Collections.emptyList();
+ }
+ List<String> paths =
+ ((SnapshottableWithInclusions) object).snapshotInclusions();
+ if (paths == null) {
+ return Collections.emptyList();
+ }
+ return paths;
+ }
+
+
+ private String andlog(final String label, final ObjectAdapter object) {
+ return ", " + log(label, object);
+ }
+
+ private String andlog(final String label, final Object object) {
+ return ", " + log(label, object);
+ }
+
+ /**
+ * Creates an Element representing this object, and appends it as the root element of the Document.
+ *
+ * The Document must not yet have a root element Additionally, the supplied schemaManager must be
+ * populated with any application-level namespaces referenced in the document that the parentElement
+ * resides within. (Normally this is achieved simply by using appendXml passing in a new schemaManager -
+ * see {@link #toXml()}or {@link XmlSnapshot}).
+ */
+ private Place appendXml(final ObjectAdapter object) {
+
+ LOG.debug("appendXml(" + log("obj", object) + "')");
+
+ final String fullyQualifiedClassName = object.getSpecification().getFullIdentifier();
+
+ schema.setUri(fullyQualifiedClassName); // derive
+ // URI
+ // from
+ // fully
+ // qualified
+ // name
+
+ final Place place = objectToElement(object);
+
+ final Element element = place.getXmlElement();
+ final Element xsElementElement = place.getXsdElement();
+
+ LOG.debug("appendXml(NO): add as element to XML doc");
+ getXmlDocument().appendChild(element);
+
+ LOG.debug("appendXml(NO): add as xs:element to xs:schema of the XSD document");
+ getXsdElement().appendChild(xsElementElement);
+
+ LOG.debug("appendXml(NO): set target name in XSD, derived from FQCN of obj");
+ schema.setTargetNamespace(getXsdDocument(), fullyQualifiedClassName);
+
+ LOG.debug("appendXml(NO): set schema location file name to XSD, derived from FQCN of obj");
+ final String schemaLocationFileName = fullyQualifiedClassName + ".xsd";
+ schema.assignSchema(getXmlDocument(), fullyQualifiedClassName, schemaLocationFileName);
+
+ LOG.debug("appendXml(NO): copy into snapshot obj");
+ setXmlElement(element);
+ setSchemaLocationFileName(schemaLocationFileName);
+
+ return place;
+ }
+
+ /**
+ * Creates an Element representing this object, and appends it to the supplied parentElement, provided
+ * that an element for the object is not already appended.
+ *
+ * The method uses the OID to determine if an object's element is already present. If the object is not
+ * yet persistent, then the hashCode is used instead.
+ *
+ * The parentElement must have an owner document, and should define the nof namespace. Additionally, the
+ * supplied schemaManager must be populated with any application-level namespaces referenced in the
+ * document that the parentElement resides within. (Normally this is achieved simply by using appendXml
+ * passing in a rootElement and a new schemaManager - see {@link #toXml()}or {@link XmlSnapshot}).
+ */
+ private Element appendXml(final Place parentPlace, final ObjectAdapter childObject) {
+
+ LOG.debug("appendXml(" + log("parentPlace", parentPlace) + andlog("childObj", childObject) + ")");
+
+ final Element parentElement = parentPlace.getXmlElement();
+ final Element parentXsElement = parentPlace.getXsdElement();
+
+ if (parentElement.getOwnerDocument() != getXmlDocument()) {
+ throw new IllegalArgumentException("parent XML Element must have snapshot's XML document as its owner");
+ }
+
+ LOG.debug("appendXml(Pl, NO): invoking objectToElement() for " + log("childObj", childObject));
+ final Place childPlace = objectToElement(childObject);
+ Element childElement = childPlace.getXmlElement();
+ final Element childXsElement = childPlace.getXsdElement();
+
+ LOG.debug("appendXml(Pl, NO): invoking mergeTree of parent with child");
+ childElement = mergeTree(parentElement, childElement);
+
+ LOG.debug("appendXml(Pl, NO): adding XS Element to schema if required");
+ schema.addXsElementIfNotPresent(parentXsElement, childXsElement);
+
+ return childElement;
+ }
+
+ private boolean appendXmlThenIncludeRemaining(
+ final Place parentPlace,
+ final ObjectAdapter referencedObject,
+ final Vector fieldNames,
+ final String annotation) {
+
+ LOG.debug("appendXmlThenIncludeRemaining(: " + log("parentPlace", parentPlace)
+ + andlog("referencedObj", referencedObject) + andlog("fieldNames", fieldNames) + andlog("annotation", annotation)
+ + ")");
+
+ LOG.debug("appendXmlThenIncludeRemaining(..): invoking appendXml(parentPlace, referencedObject)");
+
+ final Element referencedElement = appendXml(parentPlace, referencedObject);
+ final Place referencedPlace = new Place(referencedObject, referencedElement);
+
+ final boolean includedField = includeField(referencedPlace, fieldNames, annotation);
+
+ LOG.debug("appendXmlThenIncludeRemaining(..): invoked includeField(referencedPlace, fieldNames)"
+ + andlog("returned", "" + includedField));
+
+ return includedField;
+ }
+
+ private Vector elementsUnder(final Element parentElement, final String localName) {
+ final Vector v = new Vector();
+ final NodeList existingNodes = parentElement.getChildNodes();
+ for (int i = 0; i < existingNodes.getLength(); i++) {
+ final Node node = existingNodes.item(i);
+ if (!(node instanceof Element)) {
+ continue;
+ }
+ final Element element = (Element) node;
+ if (localName.equals("*") || element.getLocalName().equals(localName)) {
+ v.addElement(element);
+ }
+ }
+ return v;
+ }
+
+ public ObjectAdapter getObject() {
+ return rootPlace.getObject();
+ }
+
+ public XmlSchema getSchema() {
+ return schema;
+ }
+
+ /**
+ * The name of the <code>xsi:schemaLocation</code> in the XML document.
+ *
+ * Taken from the <code>fullyQualifiedClassName</code> (which also is used as the basis for the
+ * <code>targetNamespace</code>.
+ *
+ * Populated in {@link #appendXml(ObjectAdapter)}.
+ */
+ public String getSchemaLocationFileName() {
+ return schemaLocationFileName;
+ }
+
+ public Document getXmlDocument() {
+ return xmlDocument;
+ }
+
+ /**
+ * The root element of {@link #getXmlDocument()}. Returns <code>null</code> until the snapshot has
+ * actually been built.
+ */
+ public Element getXmlElement() {
+ return xmlElement;
+ }
+
+ public Document getXsdDocument() {
+ return xsdDocument;
+ }
+
+ /**
+ * The root element of {@link #getXsdDocument()}. Returns <code>null</code> until the snapshot has
+ * actually been built.
+ */
+ public Element getXsdElement() {
+ return xsdElement;
+ }
+
+ public void include(final String path) {
+ include(path, null);
+ }
+
+ public void include(final String path, final String annotation) {
+
+ // tokenize into successive fields
+ final Vector fieldNames = new Vector();
+ for (final StringTokenizer tok = new StringTokenizer(path, "/"); tok.hasMoreTokens();) {
+ final String token = tok.nextToken();
+
+ LOG.debug("include(..): " + log("token", token));
+ fieldNames.addElement(token);
+ }
+
+ LOG.debug("include(..): " + log("fieldNames", fieldNames));
+
+ // navigate first field, from the root.
+ LOG.debug("include(..): invoking includeField");
+ includeField(rootPlace, fieldNames, annotation);
+ }
+
+ /**
+ * @return true if able to navigate the complete vector of field names successfully; false if a field
+ * could not be located or it turned out to be a value.
+ */
+ private boolean includeField(final Place place, final Vector fieldNames, final String annotation) {
+
+ LOG.debug("includeField(: " + log("place", place) + andlog("fieldNames", fieldNames) + andlog("annotation", annotation)
+ + ")");
+
+ final ObjectAdapter object = place.getObject();
+ final Element xmlElement = place.getXmlElement();
+
+ // we use a copy of the path so that we can safely traverse collections
+ // without side-effects
+ final Vector originalNames = fieldNames;
+ final Vector names = new Vector();
+ for (final java.util.Enumeration e = originalNames.elements(); e.hasMoreElements();) {
+ names.addElement(e.nextElement());
+ }
+
+ // see if we have any fields to process
+ if (names.size() == 0) {
+ return true;
+ }
+
+ // take the first field name from the list, and remove
+ final String fieldName = (String) names.elementAt(0);
+ names.removeElementAt(0);
+
+ LOG.debug("includeField(Pl, Vec, Str):" + log("processing field", fieldName) + andlog("left", "" + names.size()));
+
+ // locate the field in the object's class
+ final ObjectSpecification nos = object.getSpecification();
+ ObjectAssociation field = null;
+ try {
+ // HACK: really want a ObjectSpecification.hasField method to
+ // check first.
+ field = nos.getAssociation(fieldName);
+ } catch (final ObjectSpecificationException ex) {
+ LOG.info("includeField(Pl, Vec, Str): could not locate field, skipping");
+ return false;
+ }
+
+ // locate the corresponding XML element
+ // (the corresponding XSD element will later be attached to xmlElement
+ // as its userData)
+ LOG.debug("includeField(Pl, Vec, Str): locating corresponding XML element");
+ final Vector xmlFieldElements = elementsUnder(xmlElement, field.getId());
+ if (xmlFieldElements.size() != 1) {
+ LOG.info("includeField(Pl, Vec, Str): could not locate " + log("field", field.getId())
+ + andlog("xmlFieldElements.size", "" + xmlFieldElements.size()));
+ return false;
+ }
+ final Element xmlFieldElement = (Element) xmlFieldElements.elementAt(0);
+
+ if (names.size() == 0 && annotation != null) {
+ // nothing left in the path, so we will apply the annotation now
+ isisMetaModel.setAnnotationAttribute(xmlFieldElement, annotation);
+ }
+
+ final Place fieldPlace = new Place(object, xmlFieldElement);
+
+ if (field instanceof OneToOneAssociation) {
+ if (field.getSpecification().getAssociations().size() == 0) {
+ LOG.debug("includeField(Pl, Vec, Str): field is value; done");
+ return false;
+ }
+
+ LOG.debug("includeField(Pl, Vec, Str): field is 1->1");
+
+ final OneToOneAssociation oneToOneAssociation = ((OneToOneAssociation) field);
+ final ObjectAdapter referencedObject = oneToOneAssociation.get(fieldPlace.getObject());
+
+ if (referencedObject == null) {
+ return true; // not a failure if the reference was null
+ }
+
+ final boolean appendedXml = appendXmlThenIncludeRemaining(fieldPlace, referencedObject, names,
+ annotation);
+ LOG.debug("includeField(Pl, Vec, Str): 1->1: invoked appendXmlThenIncludeRemaining for "
+ + log("referencedObj", referencedObject) + andlog("returned", "" + appendedXml));
+
+ return appendedXml;
+
+ } else if (field instanceof OneToManyAssociation) {
+ LOG.debug("includeField(Pl, Vec, Str): field is 1->M");
+
+ final OneToManyAssociation oneToManyAssociation = (OneToManyAssociation) field;
+ final ObjectAdapter collection = oneToManyAssociation.get(fieldPlace.getObject());
+ final CollectionFacet facet = collection.getSpecification().getFacet(CollectionFacet.class);
+
+ LOG.debug("includeField(Pl, Vec, Str): 1->M: " + log("collection.size", "" + facet.size(collection)));
+ boolean allFieldsNavigated = true;
+ final Enumeration elements = facet.elements(collection);
+ while (elements.hasMoreElements()) {
+ final ObjectAdapter referencedObject = (ObjectAdapter) elements.nextElement();
+ final boolean appendedXml = appendXmlThenIncludeRemaining(fieldPlace, referencedObject, names, annotation);
+ LOG.debug("includeField(Pl, Vec, Str): 1->M: + invoked appendXmlThenIncludeRemaining for "
+ + log("referencedObj", referencedObject) + andlog("returned", "" + appendedXml));
+ allFieldsNavigated = allFieldsNavigated && appendedXml;
+ }
+ LOG.debug("includeField(Pl, Vec, Str): " + log("returning", "" + allFieldsNavigated));
+ return allFieldsNavigated;
+ }
+
+ return false; // fall through, shouldn't get here but just in
+ // case.
+ }
+
+ private String log(final String label, final ObjectAdapter object) {
+ return log(label, (object == null ? "(null)" : object.titleString() + "[" + oidOrHashCode(object) + "]"));
+ }
+
+ private String log(final String label, final Object object) {
+ return (label == null ? "?" : label) + "='" + (object == null ? "(null)" : object.toString()) + "'";
+ }
+
+ /**
+ * Merges the tree of Elements whose root is <code>childElement</code> underneath the
+ * <code>parentElement</code>.
+ *
+ * If the <code>parentElement</code> already has an element that matches the <code>childElement</code>,
+ * then recursively attaches the grandchildren instead.
+ *
+ * The element returned will be either the supplied <code>childElement</code>, or an existing child
+ * element if one already existed under <code>parentElement</code>.
+ */
+ private Element mergeTree(final Element parentElement, final Element childElement) {
+
+ LOG.debug("mergeTree(" + log("parent", parentElement) + andlog("child", childElement));
+
+ final String childElementOid = isisMetaModel.getAttribute(childElement, "oid");
+
+ LOG.debug("mergeTree(El,El): " + log("childOid", childElementOid));
+ if (childElementOid != null) {
+
+ // before we add the child element, check to see if it is already
+ // there
+ LOG.debug("mergeTree(El,El): check if child already there");
+ final Vector existingChildElements = elementsUnder(parentElement, childElement.getLocalName());
+ for (final Enumeration childEnum = existingChildElements.elements(); childEnum.hasMoreElements();) {
+ final Element possibleMatchingElement = (Element) childEnum.nextElement();
+
+ final String possibleMatchOid = isisMetaModel.getAttribute(possibleMatchingElement, "oid");
+ if (possibleMatchOid == null || !possibleMatchOid.equals(childElementOid)) {
+ continue;
+ }
+
+ LOG.debug("mergeTree(El,El): child already there; merging grandchildren");
+
+ // match: transfer the children of the child (grandchildren) to
+ // the
+ // already existing matching child
+ final Element existingChildElement = possibleMatchingElement;
+ final Vector grandchildrenElements = elementsUnder(childElement, "*");
+ for (final Enumeration grandchildEnum = grandchildrenElements.elements(); grandchildEnum.hasMoreElements();) {
+ final Element grandchildElement = (Element) grandchildEnum.nextElement();
+ childElement.removeChild(grandchildElement);
+
+ LOG.debug("mergeTree(El,El): merging " + log("grandchild", grandchildElement));
+
+ mergeTree(existingChildElement, grandchildElement);
+ }
+ return existingChildElement;
+ }
+ }
+
+ parentElement.appendChild(childElement);
+ return childElement;
+ }
+
+ Place objectToElement(final ObjectAdapter object) {
+
+ LOG.debug("objectToElement(" + log("object", object) + ")");
+
+ final ObjectSpecification nos = object.getSpecification();
+
+ LOG.debug("objectToElement(NO): create element and nof:title");
+ final Element element = schema.createElement(getXmlDocument(), nos.getShortIdentifier(), nos.getFullIdentifier(), nos
+ .getSingularName(), nos.getPluralName());
+ isisMetaModel.appendNofTitle(element, object.titleString());
+
+ LOG.debug("objectToElement(NO): create XS element for NOF class");
+ final Element xsElement = schema.createXsElementForNofClass(getXsdDocument(), element, topLevelElementWritten, FacetUtil
+ .getFacetsByType(nos));
+
+ // hack: every element in the XSD schema apart from first needs minimum cardinality setting.
+ topLevelElementWritten = true;
+
+ final Place place = new Place(object, element);
+
+ isisMetaModel.setAttributesForClass(element, oidOrHashCode(object).toString());
+
+ final List<ObjectAssociation> fields = nos.getAssociations();
+ LOG.debug("objectToElement(NO): processing fields");
+ eachField: for (int i = 0; i < fields.size(); i++) {
+ final ObjectAssociation field = fields.get(i);
+ final String fieldName = field.getId();
+
+ LOG.debug("objectToElement(NO): " + log("field", fieldName));
+
+ // Skip field if we have seen the name already
+ // This is a workaround for getLastActivity(). This method exists
+ // in AbstractObjectAdapter, but is not (at some level) being picked
+ // up
+ // by the dot-net reflector as a property. On the other hand it does
+ // exist as a field in the meta model (ObjectSpecification).
+ //
+ // Now, to re-expose the lastactivity field for .Net, a
+ // deriveLastActivity()
+ // has been added to BusinessObject. This caused another field of
+ // the
+ // same name, ultimately breaking the XSD.
+ for (int j = 0; j < i; j++) {
+ if (fieldName.equals(fields.get(i).getName())) {
+ LOG.debug("objectToElement(NO): " + log("field", fieldName) + " SKIPPED");
+ continue eachField;
+ }
+ }
+
+ Element xmlFieldElement = getXmlDocument().createElementNS(schema.getUri(), // scoped by namespace
+ // of class of
+ // containing object
+ schema.getPrefix() + ":" + fieldName);
+
+ Element xsdFieldElement = null;
+
+ if (field.getSpecification().containsFacet(ValueFacet.class)) {
+ LOG.debug("objectToElement(NO): " + log("field", fieldName) + " is value");
+
+ final ObjectSpecification fieldNos = field.getSpecification();
+ // skip fields of type XmlValue
+ if (fieldNos == null) {
+ continue eachField;
+ }
+ if (fieldNos.getFullIdentifier() != null && fieldNos.getFullIdentifier().endsWith("XmlValue")) {
+ continue eachField;
+ }
+
+ final OneToOneAssociation valueAssociation = ((OneToOneAssociation) field);
+ final Element xmlValueElement = xmlFieldElement; // more meaningful locally scoped name
+
+ ObjectAdapter value;
+ try {
+ value = valueAssociation.get(object);
+
+ final ObjectSpecification valueNos = value.getSpecification();
+
+ // XML
+ isisMetaModel.setAttributesForValue(xmlValueElement, valueNos.getShortIdentifier());
+
+ // return parsed string, else encoded string, else title.
+ String valueStr;
+ ParseableFacet parseableFacet = fieldNos.getFacet(ParseableFacet.class);
+ EncodableFacet encodeableFacet = fieldNos.getFacet(EncodableFacet.class);
+ if(parseableFacet != null) {
+ valueStr = parseableFacet.parseableTitle(value);
+ } else if(encodeableFacet != null) {
+ valueStr = encodeableFacet.toEncodedString(value);
+ } else {
+ valueStr = value.titleString();
+ }
+
+ final boolean notEmpty = (valueStr.length() > 0);
+ if (notEmpty) {
+ xmlValueElement.appendChild(getXmlDocument().createTextNode(valueStr));
+ } else {
+ isisMetaModel.setIsEmptyAttribute(xmlValueElement, true);
+ }
+
+ } catch (final Exception ex) {
+ LOG.warn("objectToElement(NO): " + log("field", fieldName)
+ + ": getField() threw exception - skipping XML generation");
+ }
+
+ // XSD
+ xsdFieldElement = schema.createXsElementForNofValue(xsElement, xmlValueElement, FacetUtil
+ .getFacetsByType(valueAssociation));
+
+ } else if (field instanceof OneToOneAssociation) {
+
+ LOG.debug("objectToElement(NO): " + log("field", fieldName) + " is OneToOneAssociation");
+
+ final OneToOneAssociation oneToOneAssociation = ((OneToOneAssociation) field);
+ final String fullyQualifiedClassName = nos.getFullIdentifier();
+ final Element xmlReferenceElement = xmlFieldElement; // more meaningful locally scoped name
+
+ ObjectAdapter referencedObjectAdapter;
+
+ try {
+ referencedObjectAdapter = oneToOneAssociation.get(object);
+
+ // XML
+ isisMetaModel.setAttributesForReference(xmlReferenceElement, schema.getPrefix(), fullyQualifiedClassName);
+
+ if (referencedObjectAdapter != null) {
+ isisMetaModel.appendNofTitle(xmlReferenceElement, referencedObjectAdapter.titleString());
+ } else {
+ isisMetaModel.setIsEmptyAttribute(xmlReferenceElement, true);
+ }
+
+ } catch (final Exception ex) {
+ LOG.warn("objectToElement(NO): " + log("field", fieldName)
+ + ": getAssociation() threw exception - skipping XML generation");
+ }
+
+ // XSD
+ xsdFieldElement = schema.createXsElementForNofReference(xsElement, xmlReferenceElement, oneToOneAssociation
+ .getSpecification().getFullIdentifier(), FacetUtil.getFacetsByType(oneToOneAssociation));
+
+ } else if (field instanceof OneToManyAssociation) {
+
+ LOG.debug("objectToElement(NO): " + log("field", fieldName) + " is OneToManyAssociation");
+
+ final OneToManyAssociation oneToManyAssociation = (OneToManyAssociation) field;
+ final Element xmlCollectionElement = xmlFieldElement; // more meaningful locally scoped name
+
+ ObjectAdapter collection;
+ try {
+ collection = oneToManyAssociation.get(object);
+ final ObjectSpecification referencedTypeNos = oneToManyAssociation.getSpecification();
+ final String fullyQualifiedClassName = referencedTypeNos.getFullIdentifier();
+
+ // XML
+ isisMetaModel.setNofCollection(xmlCollectionElement, schema.getPrefix(), fullyQualifiedClassName, collection);
+ } catch (final Exception ex) {
+ LOG.warn("objectToElement(NO): " + log("field", fieldName)
+ + ": get(obj) threw exception - skipping XML generation");
+ }
+
+ // XSD
+ xsdFieldElement = schema.createXsElementForNofCollection(xsElement, xmlCollectionElement, oneToManyAssociation
+ .getSpecification().getFullIdentifier(), FacetUtil.getFacetsByType(oneToManyAssociation));
+
+ } else {
+ LOG.info("objectToElement(NO): " + log("field", fieldName) + " is unknown type; ignored");
+ continue;
+ }
+
+ if (xsdFieldElement != null) {
+ Place.setXsdElement(xmlFieldElement, xsdFieldElement);
+ }
+
+ // XML
+ LOG.debug("objectToElement(NO): invoking mergeTree for field");
+ xmlFieldElement = mergeTree(element, xmlFieldElement);
+
+ // XSD
+ if (xsdFieldElement != null) {
+ LOG.debug("objectToElement(NO): adding XS element for field to schema");
+ schema.addFieldXsElement(xsElement, xsdFieldElement);
+ }
+ }
+
+ return place;
+ }
+
+ private String oidOrHashCode(final ObjectAdapter object) {
+ final Oid oid = object.getOid();
+ /*
+ * if (oid == null) { return "" + object.hashCode(); }
+ */
+ if (oid instanceof DirectlyStringableOid) {
+ DirectlyStringableOid directlyStringableOid = (DirectlyStringableOid) oid;
+ return directlyStringableOid.enString();
+ } else {
+ return oid.toString();
+ }
+ /*
+ * InlineTransferableWriter itw = new InlineTransferableWriter(); oid.writeData(itw); itw.close();
+ * return itw.toString();
+ */
+ }
+
+ /**
+ * @param schemaLocationFileName
+ * The schemaLocationFileName to set.
+ */
+ private void setSchemaLocationFileName(final String schemaLocationFileName) {
+ this.schemaLocationFileName = schemaLocationFileName;
+ }
+
+ /**
+ * @param xmlElement
+ * The xmlElement to set.
+ */
+ private void setXmlElement(final Element xmlElement) {
+ this.xmlElement = xmlElement;
+ }
+
+}
Copied: incubator/isis/trunk/core/runtime/src/main/java/org/apache/isis/core/runtime/snapshot/XsMetaModel.java (from r1083695, incubator/isis/trunk/runtimes/dflt/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/snapshot/XsMetaModel.java)
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/core/runtime/src/main/java/org/apache/isis/core/runtime/snapshot/XsMetaModel.java?p2=incubator/isis/trunk/core/runtime/src/main/java/org/apache/isis/core/runtime/snapshot/XsMetaModel.java&p1=incubator/isis/trunk/runtimes/dflt/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/snapshot/XsMetaModel.java&r1=1083695&r2=1085690&rev=1085690&view=diff
==============================================================================
--- incubator/isis/trunk/runtimes/dflt/runtime/src/main/java/org/apache/isis/runtimes/dflt/runtime/snapshot/XsMetaModel.java (original)
+++ incubator/isis/trunk/core/runtime/src/main/java/org/apache/isis/core/runtime/snapshot/XsMetaModel.java Sat Mar 26 11:07:04 2011
@@ -18,7 +18,7 @@
*/
-package org.apache.isis.runtimes.dflt.runtime.snapshot;
+package org.apache.isis.core.runtime.snapshot;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
Modified: incubator/isis/trunk/core/runtime/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/core/runtime/src/site/apt/index.apt?rev=1085690&r1=1085689&r2=1085690&view=diff
==============================================================================
--- incubator/isis/trunk/core/runtime/src/site/apt/index.apt (original)
+++ incubator/isis/trunk/core/runtime/src/site/apt/index.apt Sat Mar 26 11:07:04 2011
@@ -17,16 +17,10 @@
-ProgModel
+Runtime
- The <core progmodel> provides a set of reusable elements (implementations of
- the <<<FacetFactory>>> API) that can be reused to make up a programming model.
-
- Most of those within <this> module are in fact used in the
- default programming model, defined by the
- {{{../../defaults/progmodel/index.html}default progmodel}} module. They are
- defined within core, however, to allow custom programming models (perhaps
- extending or trimming back the default programming model) to be defined.
+ The <core runtime> module defines a set of APIs common across
+ all runtime implementations.
Documentation
Modified: incubator/isis/trunk/core/runtime/src/site/site.xml
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/core/runtime/src/site/site.xml?rev=1085690&r1=1085689&r2=1085690&view=diff
==============================================================================
--- incubator/isis/trunk/core/runtime/src/site/site.xml (original)
+++ incubator/isis/trunk/core/runtime/src/site/site.xml Sat Mar 26 11:07:04 2011
@@ -3,10 +3,10 @@
<body>
<breadcrumbs>
- <item name="Profile Store" href="index.html"/>
+ <item name="Runtime" href="index.html"/>
</breadcrumbs>
- <menu name="ProfileStore">
+ <menu name="Runtime">
<item name="About" href="index.html" />
<item name="Jottings" href="jottings.html" />
</menu>
@@ -14,9 +14,10 @@
<menu name="Core Modules">
<item name="Core Test Support" href="../testsupport/index.html" />
<item name="Core Commons" href="../commons/index.html" />
- <item name="Core MetaModel" href="../metamodel/index.html" />
- <item name="Core ProgModel" href="../progmodel/index.html" />
- <item name="Core Profilestore" href="../profilestore/index.html" />
+ <item name="Core Metamodel" href="../metamodel/index.html" />
+ <item name="Core Progmodel" href="../progmodel/index.html" />
+ <item name="Core Runtime" href="../runtime/index.html" />
+ <item name="Core Webapp" href="../webapp/index.html" />
</menu>
<menu name="Maven Reports" ref="reports"/>