0001: /*---------------- FILE HEADER ------------------------------------------
0002: This file is part of adv ebrim project.
0003: Copyright (C) 2007 by:
0004:
0005: Andreas Poth
0006: lat/lon GmbH
0007: Aennchenstr. 19
0008: 53177 Bonn
0009: Germany
0010: E-Mail: poth@lat-lon.de
0011:
0012: ---------------------------------------------------------------------------*/
0013: package de.latlon.adv;
0014:
0015: import java.io.BufferedReader;
0016: import java.io.IOException;
0017: import java.io.InputStream;
0018: import java.io.InputStreamReader;
0019: import java.net.URI;
0020: import java.net.URISyntaxException;
0021: import java.util.ArrayList;
0022: import java.util.HashMap;
0023: import java.util.LinkedList;
0024: import java.util.List;
0025: import java.util.Map;
0026: import java.util.Properties;
0027: import java.util.Queue;
0028:
0029: import javax.xml.transform.TransformerException;
0030:
0031: import org.deegree.datatypes.QualifiedName;
0032: import org.deegree.framework.log.ILogger;
0033: import org.deegree.framework.log.LoggerFactory;
0034: import org.deegree.framework.util.StringTools;
0035: import org.deegree.framework.xml.NamespaceContext;
0036: import org.deegree.framework.xml.XMLFragment;
0037: import org.deegree.framework.xml.XMLParsingException;
0038: import org.deegree.framework.xml.XMLTools;
0039: import org.deegree.ogcbase.CommonNamespaces;
0040: import org.deegree.ogcwebservices.OGCWebServiceException;
0041: import org.deegree.ogcwebservices.csw.discovery.GetRecordsDocument;
0042: import org.w3c.dom.Document;
0043: import org.w3c.dom.Element;
0044: import org.w3c.dom.NamedNodeMap;
0045: import org.w3c.dom.Node;
0046: import org.w3c.dom.NodeList;
0047:
0048: /**
0049: * Maps valid ebrim propertypaths including variables (aka aliases) e.g. $o1 to the according wfs-propertyPaths.
0050: *
0051: * @version $Revision: 1.8 $
0052: * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
0053: * @author last edited by: $Author: bezema $
0054: *
0055: * @version 1.0. $Revision: 1.8 $, $Date: 2007-06-21 13:53:57 $
0056: *
0057: * @since 2.0
0058: */
0059: public class EBRIM_Mapping {
0060: private final static ILogger LOG = LoggerFactory
0061: .getLogger(EBRIM_Mapping.class);
0062:
0063: private final Properties mapping = new Properties();
0064:
0065: private final static NamespaceContext nsContext = CommonNamespaces
0066: .getNamespaceContext();
0067:
0068: private final static String rimNS = CommonNamespaces.OASIS_EBRIMNS
0069: .toString();
0070:
0071: private final static String wrsNS = CommonNamespaces.WRS_EBRIMNS
0072: .toString();
0073:
0074: private Map<String, QualifiedName> variables;
0075:
0076: // Used to do some parsing of QNames and variables.
0077: private GetRecordsDocument gd;
0078:
0079: // the root document node to handle the prefixes.
0080: private Node rootNode = null;
0081:
0082: /**
0083: * A very important method, it allows the retrieval of the original dom tree from the xslt-processor, which in it's
0084: * turn can be used to find the prefix mappings used in the document.
0085: *
0086: * @param context
0087: * the xslt Context, which will be given by the xalan processor
0088: * @param extElem
0089: * a class encapsulating some calling parameters from the xslt script, it is not used in this class.
0090: */
0091: public void init(
0092: org.apache.xalan.extensions.XSLProcessorContext context,
0093: @SuppressWarnings("unused")
0094: org.apache.xalan.templates.ElemExtensionCall extElem) {
0095: rootNode = context.getSourceTree();
0096: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
0097: LOG.logDebug(" in init, a test to find the 'rim' prefix");
0098: URI ns = null;
0099: try {
0100: ns = XMLTools.getNamespaceForPrefix("rim", rootNode);
0101: LOG
0102: .logDebug(" The sourcetree we got from the XSLProcessorContext was the following:");
0103: LOG
0104: .logDebug("-----------------------------------------------------");
0105: XMLFragment frag = new XMLFragment((Element) rootNode);
0106: frag.prettyPrint(System.out);
0107: LOG
0108: .logDebug("-----------------------------------------------------");
0109: } catch (URISyntaxException e) {
0110: LOG
0111: .logError(
0112: "CSW (ebRIM) EBRIM_Mapping: Couldn't get a namespace for prefix rim because: ",
0113: e);
0114: } catch (TransformerException e) {
0115: LOG
0116: .logError(
0117: "CSW (ebRIM) EBRIM_Mapping: Couldn't output the sourcetree because: ",
0118: e);
0119: }
0120: if (ns != null) {
0121: LOG
0122: .logDebug(" For the 'rim:' prefix we found following ns: "
0123: + ns.toASCIIString());
0124: } else {
0125: LOG
0126: .logError("CSW (ebRIM) EBRIM_Mapping: No namespace found for 'rim:' prefix!");
0127: }
0128: }
0129: }
0130:
0131: /**
0132: * The constructor parses the configuration file 'adv_catalog.properties' containing the propertypath mappings from
0133: * ebrim to gml.
0134: *
0135: */
0136: public EBRIM_Mapping() {
0137: try {
0138: InputStream is = EBRIM_Mapping.class
0139: .getResourceAsStream("adv_catalog.properties");
0140: BufferedReader br = new BufferedReader(
0141: new InputStreamReader(is));
0142: String line = null;
0143: int lineCount = 1;
0144: while ((line = br.readLine()) != null) {
0145: line = line.trim();
0146: if (!(line.startsWith("#") || "".equals(line))) {
0147: String[] tmp = StringTools
0148: .toArray(line, "=", false);
0149: if (tmp == null) {
0150: LOG
0151: .logError(lineCount
0152: + ") Found an error, please correct following line: "
0153: + line);
0154: } else {
0155: if (tmp.length < 2) {
0156: if (tmp.length > 0) {
0157: LOG
0158: .logError(lineCount
0159: + ") No value applied for key: "
0160: + tmp[0]
0161: + ". Key-value pairs must be seperated by an '='sign.");
0162: } else {
0163: LOG
0164: .logError(lineCount
0165: + ") The : "
0166: + tmp[0]
0167: + ". Key-value pairs must be seperated by an '='sign.");
0168: }
0169: } else if (tmp.length > 2) {
0170: LOG
0171: .logError(lineCount
0172: + ") Only one seperator '=' is allowed in a key-value pair, please correct following line: "
0173: + line);
0174: } else {
0175: mapping.put(tmp[0], tmp[1]);
0176: }
0177: }
0178: }
0179: lineCount++;
0180: }
0181:
0182: } catch (IOException e) {
0183: LOG
0184: .logError(
0185: "CSW (ebRIM) EBRIM_Mapping: An error occurred while trying to parse the 'adv_catalog.properties' file.",
0186: e);
0187: e.printStackTrace();
0188: }
0189: LOG.logDebug(" The Ebrim-Mapper found following Mappings:\n"
0190: + mapping);
0191: variables = new HashMap<String, QualifiedName>();
0192: gd = new GetRecordsDocument();
0193: }
0194:
0195: /**
0196: * maps a property name of GetRecords, Delete and Update request from the catalogue schema to the underlying WFS
0197: * schema
0198: *
0199: * @param node
0200: * containing the propertyPath
0201: * @return the mapped propertypath
0202: * @throws XMLParsingException
0203: */
0204: public String mapPropertyPath(Node node) throws XMLParsingException {
0205:
0206: String propertyNode = XMLTools.getNodeAsString(node, ".",
0207: nsContext, null);
0208: propertyNode = stripRoot(propertyNode);
0209: LOG
0210: .logDebug(" The supplied xml-Node results into following (normalized) propertypath: "
0211: + propertyNode);
0212: LOG
0213: .logDebug(" EBRIMG_Mappign#mapPropertyPath: We have got the variables: "
0214: + variables.toString());
0215:
0216: // Setting the node which will be used to find the prefixes.
0217: Node prefixResolverNode = getPrefixResolverNode(node);
0218:
0219: String[] props = propertyNode.split("/");
0220: StringBuffer result = new StringBuffer("/");
0221: int count = 0;
0222: String previousMapping = null;
0223: for (String propertyName : props) {
0224: if (propertyName != null) {
0225: // check if the propertyname references a variable.
0226: String tmpVarReference = null;
0227: String mappedName = null;
0228: if (propertyName.startsWith("$")) {
0229: tmpVarReference = propertyName;
0230: if (!variables.containsKey(propertyName
0231: .substring(1))
0232: || variables.get(propertyName.substring(1)) == null) {
0233:
0234: LOG
0235: .logError("CSW (ebRIM) EBRIM_Mapping: The referenced Variable '"
0236: + propertyName
0237: + "' in the propertyNode: '"
0238: + propertyNode
0239: + "' has not been declared this can't be!");
0240: LOG
0241: .logError("CSW (ebRIM) EBRIM_Mapping: We have got the variables: "
0242: + variables.toString());
0243: } else {
0244: // get the rim/wrs object to which this variable is bound to.
0245: propertyName = createMapStringForQName(variables
0246: .get(propertyName.substring(1)));
0247: LOG
0248: .logDebug(" trying to find mapping for a property: "
0249: + propertyName
0250: + ", with found variable: "
0251: + tmpVarReference);
0252: mappedName = mapping.getProperty(propertyName);
0253: }
0254: } else if (propertyName.startsWith("@")) {
0255: if (previousMapping == null) {
0256: LOG
0257: .logError("CSW (ebRIM) EBRIM_Mapping: a propertyName may not start with the @ sign, trying to find a mapping without the @ for: "
0258: + propertyNode);
0259: mappedName = mapping.getProperty(propertyName
0260: .substring(1));
0261: } else {
0262: // first check the RegistryObject attributes
0263: // @id=app:iduri
0264: // @home=app:home
0265: // @lid=app:liduri
0266: // @objectType=app:objectType
0267: // @status=app:status
0268: LOG
0269: .logDebug(" trying to find mapping for attribute: "
0270: + propertyName);
0271: mappedName = mapping.getProperty(propertyName);
0272: if (mappedName == null || "".equals(mappedName)) {
0273: LOG
0274: .logDebug(" the single attribute had no result, trying to find mapping with the dereferenced previous property @property: "
0275: + (previousMapping + "/" + propertyName));
0276: mappedName = mapping
0277: .getProperty(previousMapping + "/"
0278: + propertyName);
0279: }
0280: }
0281: } else {
0282: LOG
0283: .logDebug(" Trying to find mapping for simple propertyName: "
0284: + propertyName);
0285: QualifiedName qName = null;
0286: try {
0287: qName = gd.parseQNameFromString(propertyName,
0288: prefixResolverNode, true);
0289: } catch (URISyntaxException e) {
0290: LOG
0291: .logError(
0292: "CSW (ebRIM) EBRIM_Mapping: Could not create QualifiedName from propertyName: "
0293: + propertyName
0294: + ", creating simple QualifiedName.",
0295: e);
0296: qName = new QualifiedName(propertyName);
0297: }
0298: propertyName = createMapStringForQName(qName);
0299: LOG
0300: .logDebug(" trying to find mapping for a property: "
0301: + propertyName);
0302: mappedName = mapping.getProperty(propertyName);
0303: }
0304: if (mappedName == null) {
0305: // Very dirty trick to map
0306: // app:slots/app:Slot/app:values/app:SlotValues/app:geometry
0307: // and app:slots/app:Slot/app:values/app:SlotValues/stringValue.
0308: // from incoming rim:ValueList/rim:Value
0309: // as well as the wrs:ValueList/wrs:AnyValue (defined in pkg-basic.xsd)
0310: if (("rim:Value".equals(propertyName) && ("rim:ValueList"
0311: .equals(previousMapping) || "wrs:ValueList"
0312: .equals(previousMapping)))
0313: || ("wrs:AnyValue".equals(propertyName) && "wrs:ValueList"
0314: .equals(previousMapping))) {
0315: if ((count + 1) != props.length) {
0316: LOG
0317: .logError("CSW (ebRIM) EBRIM_Mapping: More properties will follow this one, this is strange, because a rim:Value can only be located at the end of a propertyPath");
0318: }
0319: Node parentNode = XMLTools.getNode(node, "..",
0320: nsContext);
0321: String parent = parentNode.getLocalName();
0322:
0323: LOG
0324: .logDebug(" It seems we want to map the rim:Slot/rim:ValueList/rim:Value or rim:Slot/wrs:ValueList/wrs:AnyValue, the value of the parent of this propertyName is: "
0325: + parent);
0326: if (parent != null) {
0327: if (parent.startsWith("Property")) {// hurray a property therefore a
0328: // stringValue
0329: LOG
0330: .logDebug(parent
0331: + " starts with 'Property' we therefore map to app:stringValue.");
0332: mappedName = "app:stringValue";
0333: } else {
0334: LOG
0335: .logDebug(parent
0336: + " doesn't start with 'Property' we therefore map to app:geometry.");
0337: mappedName = "app:geometry";
0338: }
0339: }
0340: } else {
0341: LOG
0342: .logInfo("CSW (ebRIM) EBRIM_Mapping: found no mapping for: "
0343: + propertyName);
0344: mappedName = "";
0345: }
0346: }
0347: if (!"".equals(mappedName)) {
0348: // save the found Mapping, it might be needed to map the following propertyName
0349: // if it is a property (starting with @)
0350: previousMapping = propertyName;
0351: result.append(addWFSPropertyPath(mappedName,
0352: tmpVarReference, (count == 0)));
0353: if ((count + 1) != props.length) {
0354: result.append("/");
0355: }
0356: }
0357: // next property/type
0358: count++;
0359: }
0360: }
0361:
0362: return result.toString();
0363: }
0364:
0365: /**
0366: * maps the property names of given typenames in the typeNames attribute of a GetRecords request to the catalogue
0367: * schema of the underlying WFS schema
0368: *
0369: * @param node
0370: * the GetRecords request Node
0371: * @return the mapped propertypath
0372: * @throws XMLParsingException
0373: */
0374: public String mapTypeNames(Node node) throws XMLParsingException {
0375: String typeNamesAttribute = XMLTools.getNodeAsString(node, ".",
0376: nsContext, null);
0377: Map<String, QualifiedName> tmpVariables = new HashMap<String, QualifiedName>();
0378: // Setting the node which will be used to find the prefixes.
0379: Node prefixResolverNode = getPrefixResolverNode(node);
0380:
0381: List<QualifiedName> typeNames = parseTypeList(
0382: prefixResolverNode, typeNamesAttribute, tmpVariables);
0383: LOG.logDebug(" found following qNames of the typeNames: "
0384: + typeNames);
0385: // adding new aliases to the query/@typenames
0386: String newAliasPreFix = "kQhtYHHp_";
0387: StringBuffer queryTypeNameAttrSB = new StringBuffer();
0388: if (tmpVariables.size() == 0) {
0389: for (int i = 0; i < typeNames.size(); ++i) {
0390: String aliasPrefix = newAliasPreFix + i;
0391: tmpVariables.put(newAliasPreFix + i, typeNames.get(i));
0392: queryTypeNameAttrSB.append(
0393: "rim:" + typeNames.get(i).getLocalName())
0394: .append("=").append(aliasPrefix);
0395: if ((i + 1) < typeNames.size()) {
0396: queryTypeNameAttrSB.append(" ");
0397: }
0398: }
0399: }
0400:
0401: StringBuffer resultString = new StringBuffer();
0402: int qNameCounter = 0;
0403: // Because we need to reuse the member variables map, we've made a local copy of it.
0404: variables.putAll(tmpVariables);
0405: LOG
0406: .logDebug(" EBRIM_Mapping#mapTypeNames: We have got the variables: "
0407: + variables.toString());
0408: List<String> varDefs = new ArrayList<String>();
0409: for (QualifiedName qName : typeNames) {
0410: URI ns = qName.getNamespace();
0411: String prefix = qName.getPrefix();
0412: // for debugging purposes
0413: if (prefix == null) {
0414: prefix = "";
0415: } else {
0416: prefix += ":";
0417: }
0418: if (ns == null || rimNS.equals(ns.toString())) {
0419: LOG
0420: .logDebug(" We found the following namespace for the ElementSetName/@typeName: "
0421: + ns + " so we map to the prefix rim.");
0422: prefix = "rim:";
0423: }
0424: String result = mapping.getProperty(prefix
0425: + qName.getLocalName());
0426: LOG.logDebug(" for the FeatureType: " + prefix
0427: + qName.getLocalName()
0428: + " we found following mapping: " + result);
0429: if (result != null) {
0430: resultString.append(result);
0431: // get the mapped variable for this qName
0432: String var = getVariableForQName(qName, tmpVariables);
0433: if (var != null) {
0434: // resultString.append( "=" ).append( var );
0435: varDefs.add(var);
0436: }
0437: } else {
0438: LOG
0439: .logInfo("CSW (ebRIM) EBRIM_Mapping: Found no mapping for: "
0440: + prefix
0441: + qName.getLocalName()
0442: + ", so ignoring it.");
0443: }
0444: if (++qNameCounter < typeNames.size()) {
0445: resultString.append(" ");
0446: }
0447: }
0448: // append the aliases= variables to the resultstring
0449: if (varDefs.size() != 0) {
0450: LOG
0451: .logDebug(" The defined variables list is not empty, we therefore append the alias keyword to the typeName");
0452: resultString.append(" aliases=");
0453: for (int i = 0; i < varDefs.size(); ++i) {
0454: resultString.append(varDefs.get(i));
0455: if ((i + 1) < varDefs.size()) {
0456: resultString.append(" ");
0457: }
0458: }
0459: }
0460:
0461: return resultString.toString();
0462: }
0463:
0464: /**
0465: * This method take an elementSetName node and conerts it's content into a list of wfs:PropertyName nodes. Depending
0466: * on the (String) value of the elementSetNameNode (brief, summary, full) the propertyNames will have different
0467: * values. For this method to work a temporal document is builded from which one element is created, this element
0468: * will hold all child <wfs:PropertyName> elements.
0469: *
0470: * @param elementSetNameNode
0471: * the ElementSetName Node of the incoming GetRecords request.
0472: * @return a Nodelist containing <wfs:PropertyName> nodes.
0473: */
0474: public NodeList mapElementSetName(Node elementSetNameNode) {
0475:
0476: // creating an empty document, so we can append nodes to it, which will be returned as a
0477: // Nodelist to the xslt script.
0478: Document doc = XMLTools.create();
0479: Element resultElement = doc.createElement("wfs:result");
0480: try {
0481: String elementSetName = XMLTools.getNodeAsString(
0482: elementSetNameNode, ".", nsContext, null);
0483: LOG.logDebug(" Found following elementSetName: "
0484: + elementSetName);
0485: if (elementSetName != null) {
0486: // Setting the node which will be used to find the prefixes.
0487: Node prefixResolverNode = getPrefixResolverNode(elementSetNameNode);
0488: String typeNamesAttribute = XMLTools.getNodeAsString(
0489: elementSetNameNode, "@typeNames", nsContext,
0490: null);
0491: Element queryElement = (Element) elementSetNameNode
0492: .getParentNode();
0493: String queryTypeNamesAttribute = XMLTools
0494: .getNodeAsString(queryElement, "@typeNames",
0495: nsContext, null);
0496: if (queryTypeNamesAttribute == null) {
0497: LOG
0498: .logError("CSW (ebRIM) EBRIM_Mapping: no typeNames attribute found in the csw:Query element, this may not be!!!");
0499: }
0500:
0501: // First find the variables in the csw:Query/@typeNames.
0502: Map<String, QualifiedName> varsInQuery = new HashMap<String, QualifiedName>();
0503: varsInQuery.putAll(variables);
0504: // List<QualifiedName> queryTypeNames =
0505: // parseTypeList( prefixResolverNode, queryTypeNamesAttribute, varsInQuery );
0506: if (varsInQuery.size() == 0) {
0507: LOG
0508: .logError("CSW (ebRIM) EBRIM_Mapping: We found no variables in the query, something is terribly wrong");
0509: }
0510: // StringBuffer queryTypeNameAttrSB = new StringBuffer( queryTypeNamesAttribute );
0511: // boolean resetQueryTypeNames = false;
0512:
0513: if (typeNamesAttribute == null) {
0514: // if ( varsInQuery.size() == 0 ) {
0515: // resetQueryTypeNames = true;
0516: // }
0517: LOG
0518: .logDebug(" no typeNames attribute found in the csw:ElementSetName node, therefore taking the typeNames of the query node.");
0519: typeNamesAttribute = queryTypeNamesAttribute;
0520: }
0521: // if ( varsInQuery.size() == 0 && !typeNamesAttribute.equals( queryTypeNamesAttribute ) ) {
0522: // // adding new aliases to the query/@typenames
0523: // String newAliasPreFix = "kQhtYHHp_";
0524: // queryTypeNameAttrSB = new StringBuffer();
0525: // for ( int i = 0; i < queryTypeNames.size(); ++i ) {
0526: // String aliasPrefix = newAliasPreFix + i;
0527: // varsInQuery.put( newAliasPreFix + i, queryTypeNames.get( i ) );
0528: // queryTypeNameAttrSB.append( "rim:" + queryTypeNames.get( i ).getLocalName() ).append( "=" ).append(
0529: // aliasPrefix );
0530: // if ( ( i + 1 ) < queryTypeNames.size() ) {
0531: // queryTypeNameAttrSB.append( " " );
0532: // }
0533: // }
0534: // queryElement.setAttribute( "typeNames", queryTypeNameAttrSB.toString() );
0535: // }
0536:
0537: if (typeNamesAttribute != null) {
0538:
0539: Map<String, QualifiedName> vars = new HashMap<String, QualifiedName>();
0540: List<QualifiedName> typeNames = parseTypeList(
0541: prefixResolverNode, typeNamesAttribute,
0542: vars);
0543: if (vars.size() != 0
0544: && !typeNamesAttribute
0545: .equals(queryTypeNamesAttribute)) {
0546: LOG
0547: .logError("CSW (ebRIM) EBRIM_Mapping: Found variables (aliases) in the ElementSetName/@typeNames attribute this is not allowed, we will not process them.");
0548: }
0549: LOG
0550: .logDebug(" Parent of the elementSetName has a local name (should be query): "
0551: + queryElement.getLocalName());
0552: Element constraint = XMLTools.getElement(
0553: queryElement, "csw:Constraint", nsContext);
0554: if (constraint == null) {
0555: LOG
0556: .logDebug(" No contraint node found, therefore creating one.");
0557: Element a = queryElement.getOwnerDocument()
0558: .createElementNS(
0559: CommonNamespaces.CSWNS
0560: .toASCIIString(),
0561: "csw:Constraint");
0562: queryElement.getOwnerDocument().importNode(a,
0563: false);
0564: constraint = (Element) queryElement
0565: .appendChild(a);
0566: }
0567: Element filter = XMLTools.getElement(constraint,
0568: "ogc:Filter", nsContext);
0569: if (filter == null) {
0570: LOG
0571: .logDebug(" No filter node found, therefore creating one.");
0572: Element a = queryElement.getOwnerDocument()
0573: .createElementNS(
0574: CommonNamespaces.OGCNS
0575: .toASCIIString(),
0576: "ogc:Filter");
0577: queryElement.getOwnerDocument().importNode(a,
0578: false);
0579: filter = (Element) constraint.appendChild(a);
0580: }
0581: Node firstOriginalFilterNode = filter
0582: .getFirstChild();
0583: Element andNode = null;
0584: if (firstOriginalFilterNode != null) {
0585: LOG
0586: .logDebug(" The ogc:Filter has a firstChild node, therefore creatining an extra ogc:And.");
0587: Element a = queryElement.getOwnerDocument()
0588: .createElementNS(
0589: CommonNamespaces.OGCNS
0590: .toASCIIString(),
0591: "ogc:And");
0592: queryElement.getOwnerDocument().importNode(a,
0593: false);
0594: andNode = (Element) filter.appendChild(a);
0595: andNode.appendChild(firstOriginalFilterNode);
0596: }
0597: Element tmpNode = queryElement
0598: .getOwnerDocument()
0599: .createElementNS(
0600: CommonNamespaces.OGCNS
0601: .toASCIIString(), "ogc:And");
0602: queryElement.getOwnerDocument().importNode(tmpNode,
0603: false);
0604: Element topNode = null;
0605: if (andNode != null) {
0606: if (typeNames.size() > 1) {
0607: topNode = (Element) andNode
0608: .appendChild(tmpNode);
0609: } else {
0610: topNode = andNode;
0611: }
0612: } else {
0613: if (typeNames.size() > 1) {
0614: topNode = (Element) filter
0615: .appendChild(tmpNode);
0616: } else {
0617: topNode = filter;
0618: }
0619:
0620: }
0621: // a random string to be used for the extra filter.
0622:
0623: for (int i = 0; i < typeNames.size(); ++i) {
0624: QualifiedName qName = typeNames.get(i);
0625: URI ns = qName.getNamespace();
0626: String prefix = qName.getPrefix();
0627: // for debugging purposes
0628: if (prefix == null) {
0629: prefix = "";
0630: } else {
0631: prefix += ":";
0632: }
0633: if (ns == null || rimNS.equals(ns.toString())) {
0634: LOG
0635: .logDebug(" We found the following namespace for the ElementSetName/@typeName: "
0636: + ns
0637: + " so we map to the prefix rim.");
0638: prefix = "rim:";
0639: }
0640: String result = mapping.getProperty(prefix
0641: + qName.getLocalName());
0642: LOG.logDebug(" for the FeatureType: " + prefix
0643: + qName.getLocalName()
0644: + " we found following mapping: "
0645: + result);
0646: if (result != null) {
0647: if (!"app:RegistryObject".equals(result)) {
0648: LOG
0649: .logError("CSW (ebRIM) EBRIM_Mapping: the given typeName is not a RegistryObject, and can therefore not be returned: "
0650: + prefix
0651: + qName.getLocalName());
0652: } else {
0653: String aliasPrefix = getVariableForQName(
0654: qName, varsInQuery);
0655: LOG
0656: .logDebug(" in elementSetName found alias: "
0657: + aliasPrefix
0658: + " for the typename: "
0659: + qName.getLocalName());
0660: if (aliasPrefix == null
0661: || "".equals(aliasPrefix)) {
0662: LOG
0663: .logError("CSW (ebRIM) EBRIM_Mapping: in elementSetName found no alias for the typeName: "
0664: + qName
0665: .getLocalName()
0666: + " this cannot be!");
0667: }
0668:
0669: //
0670: appendRegistryObjects(resultElement,
0671: "/$" + aliasPrefix);
0672: //appendRegistryObjects( resultElement, elementSetName, "/" + result );
0673:
0674: // now appending an ogc:PropertyIsEqual to the ogc:Or node of the ogc:Filter
0675: tmpNode = queryElement
0676: .getOwnerDocument()
0677: .createElementNS(
0678: CommonNamespaces.OGCNS
0679: .toASCIIString(),
0680: "ogc:PropertyIsEqualTo");
0681: queryElement.getOwnerDocument()
0682: .importNode(tmpNode, false);
0683: Element equalTo = (Element) topNode
0684: .appendChild(tmpNode);
0685: equalTo.setAttribute("matchCase",
0686: "true");
0687:
0688: // create the propertyName node referencing the app:RegistryObject/app:type
0689: tmpNode = queryElement
0690: .getOwnerDocument()
0691: .createElementNS(
0692: CommonNamespaces.OGCNS
0693: .toASCIIString(),
0694: "ogc:PropertyName");
0695: queryElement.getOwnerDocument()
0696: .importNode(tmpNode, false);
0697: Element propName = (Element) equalTo
0698: .appendChild(tmpNode);
0699: XMLTools.setNodeValue(propName, "$"
0700: + aliasPrefix + "/rim:type");
0701:
0702: // create the literal (localname) node to which the propertyname
0703: // app:RegistryObject/app:type should match
0704: tmpNode = queryElement
0705: .getOwnerDocument()
0706: .createElementNS(
0707: CommonNamespaces.OGCNS
0708: .toASCIIString(),
0709: "ogc:Literal");
0710: queryElement.getOwnerDocument()
0711: .importNode(tmpNode, false);
0712: Element literal = (Element) equalTo
0713: .appendChild(tmpNode);
0714: XMLTools.setNodeValue(literal, qName
0715: .getLocalName());
0716:
0717: // define a new alias for the typeNames
0718: // queryTypeNameAttrSB.append( "rim:" + qName.getLocalName() ).append( "=" ).append(
0719: // aliasPrefix );
0720: // if ( ( i + 1 ) < typeNames.size() ) {
0721: // queryTypeNameAttrSB.append( " " );
0722: // }
0723:
0724: }
0725: } else {
0726: LOG
0727: .logInfo("CSW (ebRIM) EBRIM_Mapping: Found no mapping for: "
0728: + prefix
0729: + qName.getLocalName()
0730: + ", so ignoring it.");
0731: }
0732: }
0733: // add the typeNames attribute to the QueryElement
0734: // if ( resetQueryTypeNames ) {
0735: // queryElement.setAttribute( "typeNames", queryTypeNameAttrSB.toString() );
0736: // }
0737: // if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
0738: // XMLFragment docTest = new XMLFragment( queryElement );
0739: // LOG.logDebug( " newly created query Element: \n"
0740: // + docTest.getAsPrettyString() );
0741: // }
0742: }
0743: }
0744: } catch (XMLParsingException e) {
0745: LOG
0746: .logError(
0747: "CSW (ebRIM) EBRIM_Mapping: following error occured while trying to map elementSetName node",
0748: e);
0749: }
0750: NodeList nodeList = resultElement.getChildNodes();
0751: for (int i = 0; i < nodeList.getLength(); ++i) {
0752: LOG.logDebug(" Node " + i + " has a localName: "
0753: + nodeList.item(i).getLocalName());
0754: }
0755:
0756: return resultElement.getChildNodes();
0757: }
0758:
0759: /**
0760: * Maps the typename of the given Element if the targetNamespace attribute of the given Node equals the rimNS.
0761: *
0762: * @param typeNameElement
0763: * the TypeName Element inside a DescribeRecord request.
0764: * @return the mapping of the featureType requested or an empty string (e.g. "").
0765: */
0766: public String mapTypeNameElement(Node typeNameElement) {
0767: String typeNameValue = null;
0768: if (typeNameElement != null) {
0769: try {
0770: String targetNamespace = XMLTools
0771: .getRequiredNodeAsString(typeNameElement,
0772: "@targetNamespace", nsContext);
0773: if (rimNS.equals(targetNamespace)) {
0774: typeNameValue = XMLTools.getNodeAsString(
0775: typeNameElement, ".", nsContext, null);
0776: if (typeNameValue != null) {
0777: typeNameValue = stripRoot(typeNameValue.trim());
0778: int index = typeNameValue.lastIndexOf(":");
0779: if (index != -1) {
0780: typeNameValue = typeNameValue
0781: .substring(index);
0782: }
0783: typeNameValue = mapping.getProperty("rim:"
0784: + typeNameValue);
0785: }
0786: } else {
0787: LOG
0788: .logDebug(" The given namespace: "
0789: + targetNamespace
0790: + " can not be mapped to the rim namespace: "
0791: + rimNS + " so no mapping is done");
0792: }
0793: } catch (XMLParsingException e) {
0794: LOG.logInfo(e.getMessage());
0795: }
0796: }
0797: if (typeNameValue == null) {
0798: typeNameValue = "";
0799: }
0800: return typeNameValue;
0801:
0802: }
0803:
0804: /**
0805: * Searches for a given qName in the given map and removes the mapping if it is found.
0806: *
0807: * @param qName
0808: * to search for
0809: * @param tmpVariables
0810: * some temporary variables
0811: * @return the mapped variable or <code>null</code> if none was found.
0812: */
0813: private String getVariableForQName(QualifiedName qName,
0814: Map<String, QualifiedName> tmpVariables) {
0815: if (tmpVariables.containsValue(qName)) {
0816: for (String variable : tmpVariables.keySet()) {
0817: if (qName.equals(tmpVariables.get(variable))) {
0818: tmpVariables.remove(variable);
0819: return variable;
0820: }
0821: }
0822: }
0823: return null;
0824: }
0825:
0826: /**
0827: * A simple method to split the given typeNamesAttribute in to type names and finds the optional variables inside
0828: * them.
0829: *
0830: * @param node
0831: * the context node which will be used to search for the prefixes.
0832: * @param typeNamesAttribute
0833: * the String containing the typenames attribute values.
0834: * @param vars
0835: * a map in which the found variables will be stored
0836: * @return a list with typenames parsed from the typeNamesAttribute String, if no typenames were found the size will
0837: * be 0.
0838: */
0839: private List<QualifiedName> parseTypeList(Node node,
0840: String typeNamesAttribute, Map<String, QualifiedName> vars) {
0841: LOG.logDebug(" Trying to map following typeName: "
0842: + typeNamesAttribute);
0843: // System.out.println( "einmal: " + root );
0844: // DOMPrinter.printNode( root, "");
0845: String[] splitter = typeNamesAttribute.split(" ");
0846: List<QualifiedName> typeNames = new ArrayList<QualifiedName>();
0847:
0848: for (String s : splitter) {
0849: try {
0850: LOG
0851: .logDebug(" Trying to parse following typeName (with/without variables): "
0852: + s);
0853: if (!s.startsWith("$")) {
0854: gd.findVariablesInTypeName(s, node, typeNames,
0855: vars, true);
0856: } else {
0857: // Attention, I don't know if this is the wanted behavior, we loose the variable declaration.
0858: LOG
0859: .logDebug(" Because the given typeName starts with an '$'-sign, we first dereference the alias: "
0860: + s.substring(1));
0861: if (variables.containsKey(s.substring(1))) {
0862: QualifiedName qName = variables.get(s
0863: .substring(1));
0864: LOG
0865: .logDebug(" \t the alias: "
0866: + s.substring(1)
0867: + " was therefore replaced with the propertyName: "
0868: + qName.getPrefix() + ":"
0869: + qName.getLocalName());
0870: typeNames.add(qName);
0871: } else {
0872: LOG
0873: .logError("CSW (ebRIM) EBRIM_Mapping: \t the alias was not declared, this cannot be!");
0874: }
0875: }
0876:
0877: } catch (OGCWebServiceException e) {
0878: LOG.logError(e.getMessage(), e);
0879: } catch (URISyntaxException e) {
0880: LOG.logError(e.getMessage(), e);
0881: }
0882: }
0883: return typeNames;
0884: }
0885:
0886: /**
0887: *
0888: * @param mappedName
0889: * to which the appropriate propertyPath will be added.
0890: * @param variable
0891: * starting with the "$" which will replace the mappedName.
0892: * @param isFirst
0893: * true if the given mappedName was the the firstelement on the requested xpath.
0894: */
0895: private String addWFSPropertyPath(String mappedName,
0896: String variable, boolean isFirst) {
0897: StringBuffer toBeAdded = new StringBuffer();
0898: if ("app:RegistryObject".equalsIgnoreCase(mappedName)) {
0899: if (!isFirst) {
0900: toBeAdded
0901: .append("app:linkedRegistryObject/app:LINK_RegObj_RegObj/app:registryObject/");
0902: }
0903: } else {
0904: if (isFirst) {
0905: toBeAdded.append("app:RegistryObject/");
0906: }
0907: if ("app:Name".equals(mappedName)) {
0908: toBeAdded.append("app:name/");
0909: } else if ("app:Description".equalsIgnoreCase(mappedName)) {
0910: toBeAdded.append("app:description/");
0911: } else if ("app:Slot".equals(mappedName)) {
0912: toBeAdded.append("app:slots/");
0913: } else if ("app:VersionInfo".equals(mappedName)) {
0914: toBeAdded.append("app:versionInfo/");
0915: } else if ("app:ObjectRef".equals(mappedName)) {
0916: toBeAdded
0917: .append("app:auditableEvent/app:AuditableEvent/app:affectedObjects/");
0918: } else if ("app:ExtrinsicObject".equals(mappedName)) {
0919: // this is actually the rim:ExtrinsicObject/rim:ContentVersionInfo element
0920: toBeAdded.append("app:extrinsicObject");
0921: }
0922: }
0923: if (variable != null && !"".equals(variable.trim())) {
0924: mappedName = variable;
0925: }
0926: return (toBeAdded.toString() + mappedName);
0927:
0928: }
0929:
0930: /**
0931: * Recursively strips all leading '.' and '/' from the given String.
0932: *
0933: * @param toBeStripped
0934: * the String to be stripped
0935: * @return the stripped String.
0936: */
0937: private String stripRoot(String toBeStripped) {
0938: if (toBeStripped != null) {
0939: if (toBeStripped.startsWith("/")
0940: || toBeStripped.startsWith(".")) {
0941: LOG.logDebug(" stripping first character of: "
0942: + toBeStripped);
0943: return stripRoot(toBeStripped.substring(1));
0944: }
0945: }
0946: return toBeStripped;
0947: }
0948:
0949: /**
0950: * appends the given mapped elementSetName/@typeNames value according to the elementSetNameValue to the given
0951: * resultElement.
0952: *
0953: * @param resultElement
0954: * to append the <wfs:PropertyNames> to
0955: * @param elementSetNameValue
0956: * the value of the ElementSetName node (one of full ,brief, summary)
0957: * @param resultedMapping
0958: * the mapped TypeNames-Value
0959: */
0960: private void appendRegistryObjects(Element resultElement,
0961: String resultedMapping) {
0962: // if ( "full".equalsIgnoreCase( elementSetNameValue ) ) {
0963: XMLTools.appendElement(resultElement, CommonNamespaces.WFSNS,
0964: "wfs:PropertyName", resultedMapping);
0965: // } else {
0966: // XMLTools.appendElement( resultElement, CommonNamespaces.WFSNS, "wfs:PropertyName", resultedMapping
0967: // + "/app:iduri" );
0968: // XMLTools.appendElement( resultElement, CommonNamespaces.WFSNS, "wfs:PropertyName", resultedMapping
0969: // + "/app:liduri" );
0970: // XMLTools.appendElement( resultElement, CommonNamespaces.WFSNS, "wfs:PropertyName", resultedMapping
0971: // + "/app:objectType" );
0972: // XMLTools.appendElement( resultElement, CommonNamespaces.WFSNS, "wfs:PropertyName", resultedMapping
0973: // + "/app:status" );
0974: // XMLTools.appendElement( resultElement, CommonNamespaces.WFSNS, "wfs:PropertyName", resultedMapping
0975: // + "/app:versionInfo" );
0976: // if ( "summary".equalsIgnoreCase( elementSetNameValue ) ) {
0977: // XMLTools.appendElement( resultElement, CommonNamespaces.WFSNS, "wfs:PropertyName", resultedMapping
0978: // + "/app:slots" );
0979: // XMLTools.appendElement( resultElement, CommonNamespaces.WFSNS, "wfs:PropertyName",
0980: // resultedMapping + "/app:name/app:Name" );
0981: // XMLTools.appendElement( resultElement, CommonNamespaces.WFSNS, "wfs:PropertyName",
0982: // resultedMapping + "/app:description/app:Description" );
0983: // }
0984: // }
0985: }
0986:
0987: /**
0988: * Sets the prefix to the localname of the given qName to rim: if the NS of the QName equals the rimNS or the qName
0989: * prefix == null (or empty) or the namespace of the given QName == null. Else the found prefix of the QName is
0990: * taken (happens for example with the wrs prefix)
0991: *
0992: * @param qName
0993: * to be parsed.
0994: * @return the prefix:localname part of the qName with prefix bound to "rim" or the qNames prefix.
0995: */
0996: private String createMapStringForQName(QualifiedName qName) {
0997: URI ns = qName.getNamespace();
0998: String prefix = qName.getPrefix();
0999: if (ns == null || rimNS.equals(ns.toString())
1000: || qName.getPrefix() == null
1001: || "".equals(qName.getPrefix().trim())) {
1002: prefix = "rim:";
1003: } else if (wrsNS.equals(ns.toString())) {
1004: prefix = CommonNamespaces.WRS_EBRIM_PREFIX + ":";
1005: }
1006: return prefix + qName.getLocalName();
1007: }
1008:
1009: /**
1010: * A simple method, which will return a node in which a prefix can be search.
1011: *
1012: * @param xsltNode
1013: * the local node from the calling xslt processor to one of the functions.
1014: * @return the original rootNode if it is not null, otherwise the given xsltNode.
1015: */
1016: private Node getPrefixResolverNode(Node xsltNode) {
1017: Node tmpNode = rootNode;
1018: Queue<Node> nodes = new LinkedList<Node>();
1019: nodes.offer(tmpNode);
1020: while (!nodes.isEmpty()) {
1021: tmpNode = nodes.poll();
1022: if (xsltNode.getNodeType() == Node.ATTRIBUTE_NODE) {
1023: NamedNodeMap nnm = tmpNode.getAttributes();
1024: for (int j = 0; j < nnm.getLength(); ++j) {
1025: if (xsltNode.isEqualNode(nnm.item(j))) {
1026: return nnm.item(j);
1027: }
1028: }
1029: } else {
1030: if (xsltNode.isEqualNode(tmpNode)) {
1031: return tmpNode;
1032: }
1033: }
1034: NodeList nl = tmpNode.getChildNodes();
1035: for (int i = 0; i < nl.getLength(); ++i) {
1036: nodes.offer(nl.item(i));
1037: }
1038: }
1039: return xsltNode;
1040: }
1041: }
|