/* * Constellation - An open source and standard compliant SDI * http://www.constellation-sdi.org * * Copyright 2014 Geomatys. * * 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.constellation.metadata.utils; import org.apache.sis.util.Classes; import org.apache.sis.util.iso.SimpleInternationalString; import org.apache.sis.util.logging.Logging; import org.constellation.util.NodeUtilities; import org.constellation.util.ReflectionUtilities; import org.opengis.util.InternationalString; import org.w3c.dom.Node; import javax.xml.bind.JAXBElement; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Utility methods used in CSW object. * * @author Guilhem Legal (Geomatys) */ public final class Utils { /** * A debugging logger. */ private static final Logger LOGGER = Logging.getLogger("org.constellation.metadata.Utils"); /** * A string constant used when we don't find a title on an object. */ public static final String UNKNOW_TITLE = "unknow title"; /** * A string constant used when we don't find an identifier on an object. */ public static final String UNKNOW_IDENTIFIER = "unknow_identifier"; private Utils() {} /** * This method try to find a title for this object. * if the object is a ISO19115:Metadata or CSW:Record we know were to search the title, * else we try to find a getName(), getTitle(), or getId() method. * * @param obj the object for which we want a title. * * @return the founded title or UNKNOW_TITLE */ public static String findTitle(final Object obj) { //here we try to get the title String title = UNKNOW_TITLE; final List<String> paths = new ArrayList<>(); paths.add("ISO 19115:MD_Metadata:identificationInfo:citation:title"); paths.add("ISO 19115-2:MI_Metadata:identificationInfo:citation:title"); paths.add("ISO 19115:MD_Metadata:fileIdentifier"); paths.add("ISO 19115-2:MI_Metadata:fileIdentifier"); paths.add("ISO 19115:CI_ResponsibleParty:individualName"); paths.add("ISO 19115:CI_ResponsibleParty:organisationName"); paths.add("ISO 19110:FC_FeatureCatalogue:name"); paths.add("Catalog Web Service:Record:title:content"); paths.add("Catalog Web Service:Record:identifier:content"); paths.add("Ebrim v3.0:*:name:localizedString:value"); paths.add("Ebrim v3.0:*:id"); paths.add("Ebrim v2.5:*:name:localizedString:value"); paths.add("Ebrim v2.5:*:id"); paths.add("SensorML:SensorML:member:process:id"); for (String path : paths) { Object value = ReflectionUtilities.getValuesFromPath(path, obj); if (value instanceof String && !((String)value).isEmpty()) { title = (String) value; // we stop when we have found a response break; } else if (value instanceof Collection) { Collection c = (Collection) value; Iterator it = c.iterator(); if (it.hasNext()) { Object cValue = it.next(); if (cValue instanceof String) { title = (String) cValue; break; } else if (cValue != null) { title = cValue.toString(); break; } } } else if (value != null) { LOGGER.finer("FIND TITLE => unexpected String type: " + value.getClass().getName() + "\ncurrentPath:" + path); } } return title; } /** * This method try to find a standard name for this object. * if the object is a ISO19115:Metadata we know where to search, * * @param obj the object for which we want a title. * * @return the founded standard name or {@code null} */ public static String findStandardName(final Object obj) { //here we try to get the title String standardName = null; final List<String> paths = new ArrayList<>(); paths.add("ISO 19115:MD_Metadata:metadataStandardName"); paths.add("ISO 19115-2:MI_Metadata:metadataStandardName"); paths.add("ISO 19115:CI_ResponsibleParty:xLink:href"); for (String path : paths) { Object value = ReflectionUtilities.getValuesFromPath(path, obj); if (value instanceof String) { standardName = (String) value; // we stop when we have found a response break; } else if (value != null){ LOGGER.finer("FIND Standard name => unexpected String type: " + value.getClass().getName() + "\ncurrentPath:" + path); } } return standardName; } /** * This method try to find an identifier for this object. * * @param obj the object for which we want a identifier. * * @return the founded identifier or UNKNOW_IDENTIFIER */ public static String findIdentifier(final Object obj) { if (obj instanceof Node) { return findIdentifierNode((Node)obj); } final List<String> paths = new ArrayList<>(); paths.add("ISO 19115:MD_Metadata:fileIdentifier"); paths.add("ISO 19115-2:MI_Metadata:fileIdentifier"); paths.add("ISO 19115:CI_ResponsibleParty:individualName"); paths.add("ISO 19115:CI_ResponsibleParty:organisationName"); paths.add("Catalog Web Service:Record:identifier:content"); paths.add("Ebrim v3.0:*:id"); paths.add("Ebrim v2.5:*:id"); paths.add("ISO 19110:FC_FeatureCatalogue:id"); paths.add("SensorML:SensorML:member:process:id"); return findIdentifier(obj, paths); } /** * This method try to find an identifier for this object. * * @param obj the object for which we want a identifier. * @param paths * * @return the founded identifier or UNKNOW_IDENTIFIER */ public static String findIdentifier(final Object obj, final List<String> paths) { if (obj instanceof Node) { return findIdentifierNode((Node)obj, paths); } String identifier = UNKNOW_IDENTIFIER; for (String path : paths) { Object value = ReflectionUtilities.getValuesFromPath(path, obj); // we stop when we have found a response if (value instanceof String && !((String)value).isEmpty()) { identifier = (String) value; break; } if (value instanceof InternationalString) { identifier = value.toString(); break; } else if (value instanceof Collection) { Collection c = (Collection) value; Iterator it = c.iterator(); if (it.hasNext()) { Object cValue = it.next(); if (cValue instanceof String) { identifier = (String) cValue; break; } else if (cValue != null) { identifier = cValue.toString(); break; } } } else if (value != null) { LOGGER.finer("FIND IDENTIFIER => unexpected String type: " + value.getClass().getName() + "\ncurrentPath:" + path); } } return identifier; } /** * This method try to set an identifier for this object. * * @param identifier the new identifier to set * @param object the object for which we want to set identifier. * */ public static void setIdentifier(final String identifier, final Object object) { final List<String> paths = new ArrayList<>(); paths.add("ISO 19115:MD_Metadata:fileIdentifier"); paths.add("ISO 19115-2:MI_Metadata:fileIdentifier"); paths.add("ISO 19115:CI_ResponsibleParty:organisationName"); paths.add("Catalog Web Service:Record:identifier:content"); paths.add("Ebrim v3.0:*:id"); paths.add("Ebrim v2.5:*:id"); paths.add("ISO 19110:FC_FeatureCatalogue:id"); paths.add("SensorML:SensorML:member:process:id"); for (String pathID : paths) { if (ReflectionUtilities.pathMatchObjectType(object, pathID)) { Object currentObject = object; /* * we remove the prefix path part the path always start with STANDARD:TYPE: */ pathID = pathID.substring(pathID.indexOf(':') + 1); pathID = pathID.substring(pathID.indexOf(':') + 1); while (!pathID.isEmpty()) { //we extract the current attributeName String attributeName; if (pathID.indexOf(':') != -1) { attributeName = pathID.substring(0, pathID.indexOf(':')); pathID = pathID.substring(pathID.indexOf(':') + 1); } else { attributeName = pathID; pathID = ""; } //we extract the specified type if there is one String paramClassName = null; int brackIndex = attributeName.indexOf('['); if (brackIndex != -1) { paramClassName = attributeName.substring(brackIndex + 1, attributeName.length() -1); attributeName = attributeName.substring(0, brackIndex); } if (!pathID.isEmpty()) { // we get the temporary object when navigating through the object. Object temp = currentObject; Method getter = ReflectionUtilities.getGetterFromName(attributeName, currentObject.getClass()); if (getter != null) { currentObject = ReflectionUtilities.invokeMethod(currentObject, getter); // if the object is not yet instantiate, we build it if (currentObject == null) { currentObject = ReflectionUtilities.newInstance(getter.getReturnType()); // if the build succeed we set it to the global previous object if (currentObject != null) { Method setter = ReflectionUtilities.getSetterFromName(attributeName, currentObject.getClass(), temp.getClass()); if (setter != null) { ReflectionUtilities.invokeMethod(setter, temp, currentObject); } } } else if (currentObject instanceof Collection) { if (((Collection) currentObject).size() > 0) { currentObject = ((Collection) currentObject).iterator().next(); if (currentObject instanceof JAXBElement) { currentObject = ((JAXBElement)currentObject).getValue(); } } else { if (paramClassName == null) { Class returnType = Classes.boundOfParameterizedProperty(getter); currentObject = ReflectionUtilities.newInstance(returnType); } else { try { Class paramClass = Class.forName(paramClassName); currentObject = ReflectionUtilities.newInstance(paramClass); } catch (ClassNotFoundException ex) { LOGGER.log(Level.WARNING, "unable to find the class:" + paramClassName, ex); } } // if the build succeed we set it to the global previous object if (currentObject != null) { Method setter = ReflectionUtilities.getSetterFromName(attributeName, getter.getReturnType(), temp.getClass()); if (setter != null) { ReflectionUtilities.invokeMethod(setter, temp, Arrays.asList(currentObject)); } } } } else if (currentObject instanceof JAXBElement) { currentObject = ((JAXBElement)currentObject).getValue(); } } } else { /* * we use the getter to determinate the parameter class. */ Method getter = ReflectionUtilities.getGetterFromName(attributeName, currentObject.getClass()); Class parameterClass; if (getter != null) { parameterClass = getter.getReturnType(); } else { parameterClass = String.class; } Method setter = ReflectionUtilities.getSetterFromName(attributeName, parameterClass, currentObject.getClass()); if (setter != null) { // if the parameter is a string collection if (parameterClass.equals(List.class)) { ReflectionUtilities.invokeMethod(setter, currentObject, Arrays.asList(identifier)); } else if (parameterClass.equals(InternationalString.class)){ ReflectionUtilities.invokeMethod(setter, currentObject, new SimpleInternationalString(identifier)); } else { ReflectionUtilities.invokeMethod(setter, currentObject, identifier); } return; } } } } } } /** * This method try to set an title for this object. * * @param title the new title to set. * @param object the object for which we want to set title. * */ public static void setTitle(final String title, final Object object) { final List<String> paths = new ArrayList<>(); paths.add("ISO 19115:MD_Metadata:identificationInfo[org.apache.sis.metadata.iso.identification.DefaultDataIdentification]:citation[org.apache.sis.metadata.iso.citation.DefaultCitation]:title"); paths.add("ISO 19115-2:MI_Metadata:identificationInfo[org.apache.sis.metadata.iso.identification.DefaultDataIdentification]:citation[org.apache.sis.metadata.iso.citation.DefaultCitation]:title"); //paths.add("ISO 19115:CI_ResponsibleParty:individualName"); paths.add("ISO 19115:CI_ResponsibleParty:organisationName"); paths.add("ISO 19110:FC_FeatureCatalogue:name"); paths.add("Catalog Web Service:Record:title:content"); paths.add("Ebrim v3.0:*:name:localizedString:value"); paths.add("Ebrim v2.5:*:name:localizedString:value"); paths.add("SensorML:SensorML:member:process:id"); for (String pathID : paths) { if (ReflectionUtilities.pathMatchObjectType(object, pathID)) { Object currentObject = object; /* * we remove the prefix path part the path always start with STANDARD:TYPE: */ pathID = pathID.substring(pathID.indexOf(':') + 1); pathID = pathID.substring(pathID.indexOf(':') + 1); while (!pathID.isEmpty()) { //we extract the current attributeName String attributeName; if (pathID.indexOf(':') != -1) { attributeName = pathID.substring(0, pathID.indexOf(':')); pathID = pathID.substring(pathID.indexOf(':') + 1); } else { attributeName = pathID; pathID = ""; } //we extract the specified type if there is one String paramClassName = null; int brackIndex = attributeName.indexOf('['); if (brackIndex != -1) { paramClassName = attributeName.substring(brackIndex + 1, attributeName.length() -1); attributeName = attributeName.substring(0, brackIndex); } if (!pathID.isEmpty()) { // we get the temporary object when navigating through the object. Object temp = currentObject; Method getter = ReflectionUtilities.getGetterFromName(attributeName, currentObject.getClass()); if (getter != null) { currentObject = ReflectionUtilities.invokeMethod(currentObject, getter); // if the object is not yet instantiate, we build it if (currentObject == null) { if (paramClassName == null) { currentObject = ReflectionUtilities.newInstance(getter.getReturnType()); } else { try { Class paramClass = Class.forName(paramClassName); currentObject = ReflectionUtilities.newInstance(paramClass); } catch (ClassNotFoundException ex) { LOGGER.log(Level.WARNING, "unable to find the class:" + paramClassName, ex); } } // if the build succeed we set it to the global previous object if (currentObject != null) { Method setter = ReflectionUtilities.getSetterFromName(attributeName, currentObject.getClass(), temp.getClass()); if (setter != null) { ReflectionUtilities.invokeMethod(setter, temp, currentObject); } } } else if (currentObject instanceof Collection) { if (((Collection) currentObject).size() > 0) { currentObject = ((Collection) currentObject).iterator().next(); if (currentObject instanceof JAXBElement) { currentObject = ((JAXBElement)currentObject).getValue(); } } else { if (paramClassName == null) { Class returnType = Classes.boundOfParameterizedProperty(getter); currentObject = ReflectionUtilities.newInstance(returnType); } else { try { Class paramClass = Class.forName(paramClassName); currentObject = ReflectionUtilities.newInstance(paramClass); } catch (ClassNotFoundException ex) { LOGGER.log(Level.WARNING, "unable to find the class:" + paramClassName, ex); } } // if the build succeed we set it to the global previous object if (currentObject != null) { Method setter = ReflectionUtilities.getSetterFromName(attributeName, getter.getReturnType(), temp.getClass()); if (setter != null) { ReflectionUtilities.invokeMethod(setter, temp, Arrays.asList(currentObject)); } } } } else if (currentObject instanceof JAXBElement) { currentObject = ((JAXBElement)currentObject).getValue(); } } } else { /* * we use the getter to determinate the parameter class. */ Method getter = ReflectionUtilities.getGetterFromName(attributeName, currentObject.getClass()); Class parameterClass; if (getter != null) { parameterClass = getter.getReturnType(); } else { parameterClass = String.class; } Method setter = ReflectionUtilities.getSetterFromName(attributeName, parameterClass, currentObject.getClass()); if (setter != null) { // if the parameter is a string collection if (parameterClass.equals(List.class)) { ReflectionUtilities.invokeMethod(setter, currentObject, Arrays.asList(title)); } else if (parameterClass.equals(InternationalString.class)){ ReflectionUtilities.invokeMethod(setter, currentObject, new SimpleInternationalString(title)); } else { ReflectionUtilities.invokeMethod(setter, currentObject, title); } return; } } } } } } public static String findIdentifierNode(final Node node) { final List<String> paths = new ArrayList<>(); paths.add("MD_Metadata/fileIdentifier/CharacterString"); paths.add("MI_Metadata/fileIdentifier/CharacterString"); paths.add("CI_ResponsibleParty/individualName/CharacterString"); paths.add("CI_ResponsibleParty/organisationName/CharacterString"); paths.add("Record/identifier"); paths.add("SensorML/member/System/@gml:id"); paths.add("SensorML/member/Component/@gml:id"); paths.add("*/@id"); return findIdentifierNode(node, paths); } /** * This method try to find an identifier for this Document Node. * * @param node the node object for which we want a identifier. * @param paths * * @return the founded identifier or UNKNOW_IDENTIFIER */ public static String findIdentifierNode(final Node node, final List<String> paths) { for (String path : paths) { final String[] parts = path.split("/"); if (parts[0].equals(node.getLocalName()) || parts[0].equals("*")) { List<Node> nodes = Arrays.asList(node); for (int i = 1; i < parts.length; i++) { nodes = NodeUtilities.getNodes(parts[i], nodes, -1, false); if (nodes.isEmpty()) { break; } } if (!nodes.isEmpty()) { return nodes.get(0).getTextContent(); } } } return UNKNOW_IDENTIFIER; } }