/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. 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 com.esri.gpt.catalog.gxe;
import com.esri.gpt.framework.util.Val;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Handles the loading of a Geoportal XML editor definition.
*/
public class GxeLoader {
/** class variables ========================================================= */
/** The Logger. */
private static Logger LOGGER = Logger.getLogger(GxeLoader.class.getName());
/** constructors ============================================================ */
/** Default constructor */
public GxeLoader() {}
/** methods ================================================================= */
/**
* Checks the I18N (internationalization and localization) attributes for an XmlElement.
* <br/>Any element that has a g:targetName attribute with no g:label attribute will be processed.
* <br/>A g:label attribute will be added to the element, value = "$i18nBase."+localNameForTarget
* <br/>E.g. <g:element g:targetName="dc:title" results in g:label="$i18nBase.title"
* @param context the processing context
* @param file the file that is currently being processed
* @param domNode the active DOM node
* @param gxeElement the active XmlElement
* @throws Exception if an exception occurs
*/
protected void checkI18NAttributes(GxeContext context,
GxeFile file,
Node domNode,
XmlElement gxeElement) throws Exception {
XmlAttributes attributes = gxeElement.getAttributes();
XmlAttribute attrLabel = attributes.find(GxeContext.URI_GXE,"label");
if (attrLabel == null) {
XmlAttribute attrTargetName = attributes.find(GxeContext.URI_GXE,"targetName");
if (attrTargetName != null) {
String targetName = Val.chkStr(attrTargetName.getNodeInfo().getNodeValue());
int nIdx = targetName.indexOf(":");
if (nIdx != -1) targetName = Val.chkStr(targetName.substring(nIdx+1));
if (targetName.length() > 0) {
XmlAttribute attribute = new XmlAttribute();
attribute.setParent(gxeElement);
attribute.getNodeInfo().setNamespaceURI(GxeContext.URI_GXE);
attribute.getNodeInfo().setLocalName("label");
attribute.getNodeInfo().setNodeValue("$i18nBase."+targetName);
attributes.add(attribute);
}
}
}
}
/**
* Gets the text associated with a node.
* @param domNode the subject node
* @param first if true, get the first text node associated with an element node
* @return the text (can be null)
*/
protected String getTextContent(Node domNode, boolean first) {
String text = null;
if (domNode.getNodeType() == Node.ATTRIBUTE_NODE ) {
text = domNode.getNodeValue();
if (text != null) text = Val.chkStr(text);
} else if (domNode.getNodeType() == Node.TEXT_NODE) {
text = domNode.getNodeValue();
} else if (domNode.getNodeType() == Node.CDATA_SECTION_NODE) {
text = domNode.getNodeValue();
} else if (domNode.getNodeType() == Node.ELEMENT_NODE) {
if (first) {
NodeList nl = domNode.getChildNodes();
for (int i=0;i<nl.getLength();i++) {
Node nd = nl.item(i);
if (nd.getNodeType() == Node.TEXT_NODE) {
text = nd.getNodeValue();
} else if (nd.getNodeType() == Node.CDATA_SECTION_NODE) {
text = nd.getNodeValue();
} else {
break;
}
}
} else {
text = domNode.getTextContent();
}
if (text != null) {
text = Val.chkStr(text);
if (text.length() == 0) {
text = null;
}
}
}
return text;
}
/**
* Loads a Geoportal XML editor definition.
* <br/>The file location within the definition must be set prior invoking this method.
* @param context the processing context
* @param definition the definition to be loaded
* @throws Exception if an exception occurs
*/
public void loadDefinition(GxeContext context, GxeDefinition definition) throws Exception {
context.setActiveDefinition(definition);
GxeFile file = new GxeFile();
file.setLocation(definition.getFileLocation());
file.setIsRoot(true);
Document dom = file.loadDom();
Node domRoot = file.findRoot(dom);
XmlElement gxeRoot = new XmlElement();
definition.setRootElement(gxeRoot);
this.loadXmlElement(context,file,domRoot,gxeRoot);
}
/**
* Loads the XmlAttributes associated with an XmlElement.
* @param context the processing context
* @param file the file that is currently being processed
* @param domNode the active DOM node
* @param gxeElement the active XmlElement
* @throws Exception if an exception occurs
*/
protected void loadXmlAttributes(GxeContext context,
GxeFile file,
Node domNode,
XmlElement gxeElement) throws Exception {
NamedNodeMap nnm = domNode.getAttributes();
for (int i=0; i<nnm.getLength(); i++) {
Node nd = nnm.item(i);
String nn = Val.chkStr(nd.getNodeName());
if (!nn.equals("xmlns") && (!nn.startsWith("xmlns:"))) {
XmlAttribute attribute = new XmlAttribute();
attribute.setParent(gxeElement);
this.loadXmlNodeInfo(context,file,nd,attribute);
gxeElement.ensureAttributes().add(attribute);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest("Loading: "+file.getLocation()+" "+domNode.getNodeName()+"@"+nn+"="+
Val.chkStr(attribute.getNodeInfo().getNodeValue()));
}
}
}
}
/**
* Loads the child XmlElements associated with an XmlElement.
* @param context the processing context
* @param file the file that is currently being processed
* @param domNode the active DOM node
* @param gxeElement the active XmlElement
* @throws Exception if an exception occurs
*/
protected void loadXmlChildren(GxeContext context,
GxeFile file,
Node domNode,
XmlElement gxeElement) throws Exception {
NodeList nl = domNode.getChildNodes();
for (int i=0; i<nl.getLength(); i++) {
Node nd = nl.item(i);
if (nd.getNodeType() == Node.ELEMENT_NODE) {
String ns = Val.chkStr(nd.getNamespaceURI());
String ln = Val.chkStr(nd.getLocalName());
if (ns.equals(GxeContext.URI_GXE) && ln.equals("container")) {
boolean bLoadChildren = true;
Node attr = nd.getAttributes().getNamedItemNS(GxeContext.URI_GXE,"rendered");
if (attr != null) {
String s = Val.chkStr(attr.getNodeValue());
if (s.equals("$editor.isOriginalMode")) bLoadChildren = false;
else if (s.equals("$editor.isExpertMode")) bLoadChildren = false;
else if (s.equals("$editor.isAdvancedMode")) bLoadChildren = false;
else if (s.equals("$editor.isSimplifiedMode")) bLoadChildren = true;
/*
if (s.equals("$editor.isOriginalMode")) bLoadChildren = true;
else if (s.equals("$editor.isExpertMode")) bLoadChildren = false;
else if (s.equals("$editor.isAdvancedMode")) bLoadChildren = true;
else if (s.equals("$editor.isSimplifiedMode")) bLoadChildren = false;
*/
}
if (bLoadChildren) {
this.loadXmlChildren(context,file,nd,gxeElement);
}
} else if (ns.equals(GxeContext.URI_GXE) && ln.equals("import")) {
String refLocation = null;
Node ndSrc = nd.getAttributes().getNamedItemNS(GxeContext.URI_GXE,"src");
//if (ndSrc == null) ndSrc = nd.getAttributes().getNamedItemNS(GxeContext.URI_GXE,"schemaLocation");
if (ndSrc != null) refLocation = Val.chkStr(ndSrc.getNodeValue());
if ((refLocation != null) && (refLocation.length() > 0)) {
// load the import element
XmlElement importElement = new XmlElement();
this.loadXmlAttributes(context,file,nd,importElement);
this.loadXmlChildren(context,file,nd,importElement);
// load the referenced document
XmlElement refElement = new XmlElement();
GxeFile refFile = new GxeFile(file,refLocation);
Document refDom = refFile.loadDom();
Node refRoot = refFile.findRoot(refDom);
this.loadXmlElement(context,refFile,refRoot,refElement);
String ns2 = Val.chkStr(refRoot.getNamespaceURI());
String ln2 = Val.chkStr(refRoot.getLocalName());
boolean bImportChildrenOnly = false;
if (ns2.equals(GxeContext.URI_GXE) && ln2.equals("attributeGroup")) {
bImportChildrenOnly = true;
} else if (ns2.equals(GxeContext.URI_GXE) && ln2.equals("group")) {
bImportChildrenOnly = true;
} else if (ns2.equals(GxeContext.URI_GXE) && ln2.equals("container")) {
bImportChildrenOnly = true;
}
if (bImportChildrenOnly) {
refElement.importChildren(importElement.getChildren());
gxeElement.appendChildren(refElement.getChildren());
} else {
refElement.setParent(gxeElement);
refElement.importAttributes(importElement.getAttributes(),false);
refElement.importChildren(importElement.getChildren());
gxeElement.ensureChildren().add(refElement);
}
} else {
String msg = "A <g:import> element has an empty g:src attribute: "+file.getLocation();
LOGGER.config(msg);
}
} else {
XmlElement child = new XmlElement();
child.setParent(gxeElement);
this.loadXmlElement(context,file,nd,child);
gxeElement.ensureChildren().add(child);
}
}
}
}
/**
* Loads an XmlElement.
* @param context the processing context
* @param file the file that is currently being processed
* @param domNode the active DOM node
* @param gxeElement the active XmlElement
* @throws Exception if an exception occurs
*/
protected void loadXmlElement(GxeContext context,
GxeFile file,
Node domNode,
XmlElement gxeElement) throws Exception {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.finest("Loading: "+file.getLocation()+" "+domNode.getNodeName());
}
this.loadXmlNodeInfo(context,file,domNode,gxeElement);
this.loadXmlAttributes(context,file,domNode,gxeElement);
String refLocation = null;
XmlAttribute attrExtends = gxeElement.getAttributes().find(GxeContext.URI_GXE,"extends");
if (attrExtends != null) refLocation = Val.chkStr(attrExtends.getNodeInfo().getNodeValue());
if ((refLocation != null) && (refLocation.length() > 0)) {
// load the referenced document
XmlElement refElement = new XmlElement();
GxeFile refFile = new GxeFile(file,refLocation);
Document refDom = refFile.loadDom();
Node refRoot = refFile.findRoot(refDom);
this.loadXmlElement(context,refFile,refRoot,refElement);
// extend the local element using the reference element
gxeElement.importAttributes(refElement.getAttributes(),true);
gxeElement.setChildren(refElement.getChildren());
gxeElement.getChildren().resetParent(gxeElement);
// import the children of the local element
XmlElement tmpElement = new XmlElement();
this.loadXmlChildren(context,file,domNode,tmpElement);
gxeElement.importChildren(tmpElement.getChildren());
} else {
this.loadXmlChildren(context,file,domNode,gxeElement);
}
this.checkI18NAttributes(context,file,domNode,gxeElement);
this.onXmlElementLoaded(context,file,domNode,gxeElement);
}
/**
* Loads the XmlNodeInfo associated with an XmlNode.
* @param context the processing context
* @param file the file that is currently being processed
* @param domNode the active DOM node
* @param gxeNode the active XmlNode (XmlElement or XmlAttribute)
* @throws Exception if an exception occurs
*/
protected void loadXmlNodeInfo(GxeContext context,
GxeFile file,
Node domNode,
XmlNode gxeNode) throws Exception {
XmlNodeInfo nodeInfo = gxeNode.getNodeInfo();
nodeInfo.setLocalName(domNode.getLocalName());
nodeInfo.setNamespacePrefix(domNode.getPrefix());
nodeInfo.setNamespaceURI(domNode.getNamespaceURI());
String text = this.getTextContent(domNode,true);
nodeInfo.setNodeValue(text);
}
/**
* Fired when an XmlElement has been loaded.
* @param context the processing context
* @param file the file that is currently being processed
* @param domNode the active DOM node
* @param gxeElement the active XmlElement
* @throws Exception if an exception occurs
*/
public void onXmlElementLoaded(GxeContext context,
GxeFile file,
Node domNode,
XmlElement gxeElement) throws Exception {
}
}