/*
* ModeShape (http://www.modeshape.org)
*
* Licensed 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.modeshape.sequencer.teiid.model;
import static org.modeshape.sequencer.teiid.lexicon.CoreLexicon.Namespace.URI;
import java.util.Map.Entry;
import javax.jcr.Node;
import org.modeshape.common.util.CheckArg;
import org.modeshape.common.util.StringUtil;
import org.modeshape.sequencer.teiid.VdbModel;
import org.modeshape.sequencer.teiid.VdbModel.ValidationMarker;
import org.modeshape.sequencer.teiid.lexicon.CoreLexicon;
import org.modeshape.sequencer.teiid.lexicon.CoreLexicon.JcrId;
import org.modeshape.sequencer.teiid.lexicon.VdbLexicon;
import org.modeshape.sequencer.teiid.lexicon.XmiLexicon;
import org.modeshape.sequencer.teiid.model.ReferenceResolver.UnresolvedReference;
import org.modeshape.sequencer.teiid.xmi.XmiElement;
/**
* The model object handler for the {@link org.modeshape.sequencer.teiid.lexicon.CoreLexicon.Namespace#URI core} namespace.
*/
public final class CoreModelObjectHandler extends ModelObjectHandler {
/**
* Tags not to sequence and ignore. These prefixes are not registered.
*/
private static final String[] IGNORED_MODEL_ANNOTATION_TAG_PREFIXES = {"connection", "connectionProfile", "translator"};
/**
* @param nsPrefix the prefix being checked (cannot be <code>null</code> or empty)
* @return <code>true</code> if the node is a VDB model or a Core model and the specified prefix is being ignored
* @throws Exception if there is a problem obtaining node type information from the node
*/
private boolean isIgnoredTag( final String nsPrefix ) throws Exception {
CheckArg.isNotEmpty(nsPrefix, "nsPrefix");
for (final String prefix : IGNORED_MODEL_ANNOTATION_TAG_PREFIXES) {
if (prefix.equals(nsPrefix)) {
return true;
}
}
return false;
}
/**
* @see org.modeshape.sequencer.teiid.model.ModelObjectHandler#process(org.modeshape.sequencer.teiid.xmi.XmiElement,
* javax.jcr.Node)
*/
@Override
protected void process( final XmiElement element,
final Node modelNode ) throws Exception {
CheckArg.isNotNull(element, "element");
CheckArg.isNotNull(modelNode, "node");
CheckArg.isEquals(element.getNamespaceUri(), "namespace URI", URI, "relational URI");
final String type = element.getName();
LOGGER.debug("==== CoreModelObjectHandler:process:element type={0}", type);
if (CoreLexicon.ModelId.MODEL_ANNOTATION.equals(type)) {
setProperty(modelNode, XmiLexicon.JcrId.UUID, element.getUuid());
getResolver().record(element.getUuid(), modelNode);
final ModelReader reader = getReader();
setProperty(modelNode, JcrId.MODEL_TYPE, reader.getModelType());
setProperty(modelNode, JcrId.PRIMARY_METAMODEL_URI, reader.getPrimaryMetamodelUri());
setProperty(modelNode, JcrId.DESCRIPTION, reader.getDescription());
setProperty(modelNode, JcrId.NAME_IN_SOURCE, reader.getNameInSource());
modelNode.setProperty(JcrId.MAX_SET_SIZE, reader.getMaxSetSize());
modelNode.setProperty(JcrId.VISIBLE, reader.isVisible());
modelNode.setProperty(JcrId.SUPPORTS_DISTINCT, reader.supportsDistinct());
modelNode.setProperty(JcrId.SUPPORTS_JOIN, reader.supportsJoin());
modelNode.setProperty(JcrId.SUPPORTS_ORDER_BY, reader.supportsOrderBy());
modelNode.setProperty(JcrId.SUPPORTS_OUTER_JOIN, reader.supportsOuterJoin());
modelNode.setProperty(JcrId.SUPPORTS_WHERE_ALL, reader.supportsWhereAll());
setProperty(modelNode, JcrId.PRODUCER_NAME, reader.getProducerName());
setProperty(modelNode, JcrId.PRODUCER_VERSION, reader.getProducerVersion());
setProperty(modelNode, JcrId.ORIGINAL_FILE, reader.getPath());
if (getVdbModel() != null) {
final VdbModel vdbModel = getVdbModel();
modelNode.setProperty(VdbLexicon.Model.VISIBLE, vdbModel.isVisible());
modelNode.setProperty(VdbLexicon.Model.CHECKSUM, vdbModel.getChecksum());
modelNode.setProperty(VdbLexicon.Model.BUILT_IN, vdbModel.isBuiltIn());
setProperty(modelNode, VdbLexicon.Model.DESCRIPTION, vdbModel.getDescription());
setProperty(modelNode, VdbLexicon.Model.PATH_IN_VDB, vdbModel.getPathInVdb());
setProperty(modelNode, VdbLexicon.Model.SOURCE_TRANSLATOR, vdbModel.getSourceTranslator());
setProperty(modelNode, VdbLexicon.Model.SOURCE_NAME, vdbModel.getSourceName());
setProperty(modelNode, VdbLexicon.Model.SOURCE_JNDI_NAME, vdbModel.getSourceJndiName());
// write out any model properties from vdb.xml file
for (final Entry<String, String> entry : vdbModel.getProperties().entrySet()) {
setProperty(modelNode, entry.getKey(), entry.getValue());
}
// write out and validation markers
if (!vdbModel.getProblems().isEmpty()) {
// add group node
final Node markersGroupNode = modelNode.addNode(VdbLexicon.Model.MARKERS, VdbLexicon.Model.MARKERS);
for (final ValidationMarker marker : vdbModel.getProblems()) {
final Node markerNode = markersGroupNode.addNode(VdbLexicon.Model.Marker.MARKER,
VdbLexicon.Model.Marker.MARKER);
setProperty(markerNode, VdbLexicon.Model.Marker.PATH, marker.getPath());
setProperty(markerNode, VdbLexicon.Model.Marker.MESSAGE, marker.getMessage());
setProperty(markerNode, VdbLexicon.Model.Marker.SEVERITY, marker.getSeverity().toString());
LOGGER.debug("added validation marker at path {0} and with severity of {1}",
marker.getPath(),
marker.getSeverity());
}
}
}
// process model imports
for (final XmiElement modelImport : reader.getModelImports()) {
final Node importNode = addNode(modelNode, modelImport, URI, JcrId.IMPORT);
setProperty(importNode, JcrId.MODEL_TYPE, modelImport.getAttributeValue(CoreLexicon.ModelId.MODEL_TYPE, URI));
setProperty(importNode,
JcrId.PRIMARY_METAMODEL_URI,
modelImport.getAttributeValue(CoreLexicon.ModelId.PRIMARY_METAMODEL_URI, URI));
setProperty(importNode,
JcrId.MODEL_LOCATION,
modelImport.getAttributeValue(CoreLexicon.ModelId.MODEL_LOCATION, URI));
if (getVdbModel() != null) {
for (final String importPath : getVdbModel().getImports()) {
if (importPath.endsWith(modelImport.getAttributeValue(CoreLexicon.ModelId.MODEL_LOCATION, URI))) {
setProperty(importNode, JcrId.PATH, importPath);
break;
}
}
}
}
LOGGER.debug("[end writing model annotation]");
} else if (CoreLexicon.ModelId.ANNOTATION_CONTAINER.equals(type)) {
for (final XmiElement annotation : element.getChildren()) {
if (CoreLexicon.ModelId.ANNOTATION.equals(annotation.getName())) {
String uuid = annotation.getAttributeValue(CoreLexicon.ModelId.ANNOTATED_OBJECT, URI);
if (StringUtil.isBlank(uuid)) {
// see if there is an annotated object child
for (final XmiElement child : annotation.getChildren()) {
if (CoreLexicon.ModelId.ANNOTATED_OBJECT.equals(child.getName())) {
uuid = child.getAttributeValue(CoreLexicon.ModelId.HREF, URI);
break;
}
}
}
// remove any UUID prefix
uuid = getResolver().resolveInternalReference(uuid);
if (StringUtil.isBlank(uuid)) {
LOGGER.debug("annotated object UUID is blank");
continue;
}
final Node node = getResolver().getNode(uuid);
final UnresolvedReference unresolved = ((node == null) ? getResolver().addUnresolvedReference(uuid) : null);
// description
final String description = annotation.getAttributeValue(CoreLexicon.ModelId.DESCRIPTION, URI);
if (!StringUtil.isBlank(description)) {
if (node != null) {
node.addMixin(JcrId.ANNOTATED);
setProperty(node, JcrId.DESCRIPTION, description);
} else if (unresolved != null) {
unresolved.addMixin(JcrId.ANNOTATED);
unresolved.addProperty(JcrId.DESCRIPTION, description, false);
}
}
// keywords
final String keywordsValue = annotation.getAttributeValue(CoreLexicon.ModelId.KEYWORD, URI);
if (!StringUtil.isBlank(keywordsValue)) {
if ((node != null) && !node.isNodeType(JcrId.ANNOTATED)) {
node.addMixin(JcrId.ANNOTATED);
} else if (unresolved != null) {
unresolved.addMixin(JcrId.ANNOTATED);
}
for (final String keyword : keywordsValue.split("\\s")) {
if (node != null) {
addPropertyValue(node, JcrId.KEYWORDS, keyword);
} else if (unresolved != null) {
unresolved.addProperty(JcrId.KEYWORDS, keyword, true);
}
}
}
for (final XmiElement child : annotation.getChildren()) {
boolean hasTags = false;
if (CoreLexicon.ModelId.TAGS.equals(child.getName())) {
String key = child.getAttributeValue(CoreLexicon.ModelId.KEY, URI);
if (StringUtil.isBlank(key)) {
continue;
}
final String value = child.getAttributeValue(CoreLexicon.ModelId.VALUE, URI);
final String[] parts = key.split(":", 2); // part 0 = namespace prefix, part 2 = property name
// don't process if namespace is being ignored
if (isIgnoredTag(parts[0])) {
if (node != null) {
LOGGER.debug("tag '{0}' not added as property of node '{1}'", key, node.getName());
} else if (unresolved != null) {
LOGGER.debug("tag '{0}' not added as property of node '{1}'", key, unresolved.getUuid());
}
continue; // key should be ignored
}
if ((node != null) && LOGGER.isDebugEnabled()) {
LOGGER.debug("annotated object node name '{0}' has type of '{1}' and key of '{2}'",
node.getName(),
node.getPrimaryNodeType().getName(),
key);
}
// only process when MED helper doesn't
if (!getMedHelper().process(modelNode, node, unresolved, child)) {
if (!hasTags) {
hasTags = true;
if (node != null) {
node.addMixin(JcrId.TAGS);
} else if (unresolved != null) {
unresolved.addMixin(JcrId.TAGS);
}
}
if (node != null) {
setProperty(node, key, value);
} else if (unresolved != null) {
unresolved.addProperty(key, value, false);
}
}
} else {
LOGGER.debug("Unexpected element processing an annotation: {0}", child.getName());
}
}
}
}
} else {
LOGGER.debug("**** core type of '{0}' was not processed", type);
}
}
}