tim@597: package de.intevation.gnv.artifacts.services;
tim@597:
tim@820: import java.util.ArrayList;
tim@820: import java.util.Collection;
tim@820: import java.util.Iterator;
tim@820:
tim@820: import javax.xml.xpath.XPathConstants;
tim@820:
tim@820: import org.apache.log4j.Logger;
tim@820: import org.w3c.dom.Document;
tim@820: import org.w3c.dom.Element;
tim@820: import org.w3c.dom.Node;
tim@820: import org.w3c.dom.NodeList;
tim@820:
sascha@779: import com.vividsolutions.jts.geom.Geometry;
sascha@779: import com.vividsolutions.jts.io.ParseException;
sascha@779: import com.vividsolutions.jts.io.WKTReader;
sascha@779:
sascha@779: import de.intevation.artifactdatabase.DefaultService;
sascha@779: import de.intevation.artifactdatabase.XMLUtils;
sascha@779: import de.intevation.artifacts.ArtifactNamespaceContext;
sascha@779: import de.intevation.artifacts.CallMeta;
sascha@779: import de.intevation.artifacts.ServiceFactory;
sascha@779: import de.intevation.gnv.artifacts.services.requestobjects.DefaultFIS;
sascha@779: import de.intevation.gnv.artifacts.services.requestobjects.DefaultLayer;
sascha@779: import de.intevation.gnv.artifacts.services.requestobjects.DefaultMapService;
sascha@779: import de.intevation.gnv.artifacts.services.requestobjects.DefaultParameter;
sascha@779: import de.intevation.gnv.artifacts.services.requestobjects.FIS;
sascha@779: import de.intevation.gnv.artifacts.services.requestobjects.Layer;
sascha@779: import de.intevation.gnv.artifacts.services.requestobjects.MapService;
sascha@779: import de.intevation.gnv.artifacts.services.requestobjects.Parameter;
sascha@779: import de.intevation.gnv.geobackend.base.Result;
sascha@779: import de.intevation.gnv.geobackend.base.query.QueryExecutor;
sascha@779: import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
sascha@779: import de.intevation.gnv.geobackend.base.query.exception.QueryException;
sascha@779: import de.intevation.gnv.utils.ArtifactXMLUtilities;
sascha@779:
tim@597: /**
sascha@835: * This Class Provides the Functionality to return only those
tim@820: * Artifacfactories which fulfill the conditions of the Request.
sascha@835: *
sascha@835: * This Service is used to implement the Functionality of the MV-GNV-Interface
sascha@835: * by looking if an Region of an FIS is intersecting the Area which is send
tim@820: * during the Request or which FIS belongs to the requested MapServices.
sascha@835: *
sascha@780: * @author Tim Englich
tim@597: *
tim@597: */
tim@597: public class MetaDataService extends DefaultService {
tim@597:
tim@597: /**
tim@597: * the logger, used to log exceptions and additionally information
tim@597: */
tim@597: private static Logger log = Logger.getLogger(MetaDataService.class);
tim@597:
sascha@778:
sascha@778: private final static String FIS_REGION_QUERY_ID =
tim@604: "mapviewer_interface_fis_region";
sascha@778: private final static String MAPSERVICES_HAS_FIS_QUERY_ID =
tim@604: "mapviewer_interface_mapservices_has_fis";
sascha@778: private final static String MAPSERVICES_HAS_PARAMETER_QUERY_ID =
tim@604: "mapviewer_interface_mapservices_has_parameter";
sascha@778:
sascha@778: private final static String MAPSERVICES_HAS_PARAMETER_USING_LAYER_QUERY_ID =
tim@604: "mapviewer_interface_mapservices_has_parameter_using_layer";
sascha@778:
tim@597: private static String ATTRIBUTE_ID = "id";
tim@597: private static String ATTRIBUTE_NAME = "name";
tim@597: private static String ATTRIBUTE_TYPE = "type";
tim@597: private static String ATTRIBUTE_URL = "url";
tim@597: private static String ATTRIBUTE_GROUPLAYER = "isgrouplayer";
tim@597: private static String ATTRIBUTE_PARENTID = "parentid";
tim@597: private static String ATTRIBUTE_SRS = "srs";
sascha@778:
sascha@778:
tim@597: private static String XPATH_LOACTION_NODE = "art:GetMetaData/art:location";
tim@597: private static String XPATH_MAPSERVICES_NODESET = "art:GetMetaData/" +
tim@597: "art:mapservices/" +
tim@597: "art:mapservice";
tim@597: private static String XPATH_LAYER_NODESET = "art:layer";
sascha@778:
tim@597: /**
tim@597: * The UID of this Class.
tim@597: */
tim@597: private static final long serialVersionUID = -8446483887497236372L;
tim@597:
tim@597: /**
tim@597: * Constructor
tim@597: */
tim@597: public MetaDataService() {
tim@597: super();
tim@597: }
tim@597:
tim@597: @Override
tim@597: public Document process(Document data, Object globalContext,
tim@597: CallMeta callMeta) {
tim@597: log.debug("MetaDataService.process");
tim@597: Document document = null;
tim@597: try {
tim@597: Geometry g = this.parseGeometry(data);
tim@597: Collection mapServices = this.parseMapServices(data);
sascha@778: Collection resultFIS = this.unionFIS(this.getFIS(g),
tim@597: this.getFIS(mapServices));
tim@597: document = XMLUtils.newDocument();
tim@597: this.writeFIS2Document(document, resultFIS);
ingo@792: log.debug(ArtifactXMLUtilities.writeDocument2String(document));
tim@597: } catch (MetaDataServiceException e) {
tim@597: log.error(e,e);
ingo@792: document = ArtifactXMLUtilities
tim@597: .createExceptionReport(e.getMessage(), document);
tim@597: }
tim@597: return document;
tim@597: }
sascha@778:
sascha@778: private Geometry parseGeometry(Document data)
tim@597: throws MetaDataServiceException{
tim@597: log.debug("MetaDataService.parseGeometry");
sascha@778:
tim@597: Element locationNode = (Element) XMLUtils.xpath(
tim@597: data,
tim@597: XPATH_LOACTION_NODE,
tim@597: XPathConstants.NODE,
tim@597: ArtifactNamespaceContext.INSTANCE
tim@597: );
tim@597: Geometry returnValue = null;
tim@597: if (locationNode != null) {
tim@597: String srs = locationNode.getAttribute(ATTRIBUTE_SRS);
tim@597: // TODO: use SRS to transform the Geometry to target-System.
tim@597: String geometryValue = locationNode.getTextContent();
tim@597: if (geometryValue != null){
tim@597: try {
tim@597: returnValue = new WKTReader().read(geometryValue);
tim@597: } catch (ParseException e) {
tim@597: log.error(e,e);
tim@597: throw new MetaDataServiceException("The given Geometry" +
tim@597: "String is not a " +
tim@597: "valid WKT.");
tim@597: }
tim@597: }
tim@597: }
tim@597: return returnValue;
tim@597: }
sascha@778:
tim@597: private Collection parseMapServices(Document data){
tim@597: log.debug("MetaDataService.parseMapServices");
sascha@778:
sascha@778: NodeList mapServices = (NodeList) XMLUtils.xpath(data,
tim@597: XPATH_MAPSERVICES_NODESET,
tim@597: XPathConstants.NODESET,
tim@597: ArtifactNamespaceContext.INSTANCE);
tim@597: Collection returnValue = null;
tim@597: if (mapServices != null){
tim@597: returnValue = new ArrayList(mapServices.getLength());
tim@597: for (int i = 0; i < mapServices.getLength(); i++){
tim@597: Element mapServiceNode = (Element)mapServices.item(i);
tim@597: String id = mapServiceNode.getAttribute(ATTRIBUTE_ID);
tim@597: String type = mapServiceNode.getAttribute(ATTRIBUTE_TYPE);
tim@597: String url = mapServiceNode.getAttribute(ATTRIBUTE_URL);
tim@597: Collection layer = null;
sascha@778:
sascha@778: NodeList layerNodes = (NodeList) XMLUtils.xpath(mapServiceNode,
tim@597: XPATH_LAYER_NODESET,
tim@597: XPathConstants.NODESET,
tim@597: ArtifactNamespaceContext.INSTANCE);
tim@597: if (layerNodes != null){
tim@597: layer = new ArrayList(layerNodes.getLength());
tim@597: for (int j = 0; j < layerNodes.getLength(); j++){
tim@597: Element layerNode = (Element)layerNodes.item(j);
tim@597: String layerId = layerNode.getAttribute(ATTRIBUTE_ID);
tim@597: String layerName = layerNode.getAttribute(ATTRIBUTE_NAME);
sascha@778: boolean isGroupLayer =
tim@597: Boolean.parseBoolean(layerNode
tim@597: .getAttribute(
tim@597: ATTRIBUTE_GROUPLAYER));
tim@597: String parentId = layerNode
tim@597: .getAttribute(ATTRIBUTE_PARENTID);
sascha@778:
tim@597: layer.add(new DefaultLayer(layerId,
tim@597: layerName,
tim@597: isGroupLayer,
tim@597: parentId));
tim@597: }
tim@597: }
sascha@778: MapService mapService = new DefaultMapService(id, layer,
tim@597: type, url);
tim@597: returnValue.add(mapService);
sascha@778:
tim@597: }
tim@597: }
tim@597: return returnValue;
tim@597: }
sascha@778:
sascha@778: private Collection unionFIS(Collection fromGeometry,
tim@597: Collection fromMapservices){
tim@597: log.debug("MetaDataService.unionFIS");
tim@597: Collection returnValue = null;
tim@597: if (fromGeometry == null || fromGeometry.isEmpty()){
tim@597: returnValue = fromMapservices;
tim@597: }else if (fromMapservices == null || fromMapservices.isEmpty()){
tim@597: returnValue = fromGeometry;
tim@597: }else{
sascha@778:
tim@597: returnValue = new ArrayList();
tim@597: Iterator it = fromMapservices.iterator();
tim@597: while (it.hasNext()){
tim@597: FIS fis = it.next();
tim@597: if (fromGeometry.contains(fis)){
tim@597: returnValue.add(fis);
tim@597: }
tim@597: }
tim@597: }
tim@597: return returnValue;
tim@597: }
sascha@778:
tim@597: /**
tim@597: * Puts the retrieved FIS into the given XML-Document.
tim@597: * @param document the Document where the FIS should be put in.
sascha@778: * @param fis the retrieved FIS which should be written into
tim@597: * the XML-Document.
tim@597: */
tim@597: private void writeFIS2Document(Document document, Collection fis){
sascha@778:
tim@597: if (fis != null){
tim@597: Iterator it = fis.iterator();
tim@597: XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
tim@597: document,
tim@597: ArtifactNamespaceContext.NAMESPACE_URI,
tim@597: ArtifactNamespaceContext.NAMESPACE_PREFIX
tim@597: );
tim@597: Node rootNode = creator.create("result");
tim@597: document.appendChild(rootNode);
sascha@778:
tim@597: Node factoriesNode = creator.create("factories");
tim@597: rootNode.appendChild(factoriesNode);
tim@597: while (it.hasNext()){
tim@597: FIS tmpFIS = it.next();
tim@597: Element fisNode = creator.create("factory");
tim@597: fisNode.setAttribute("art:name",tmpFIS.getID());
sascha@778:
tim@597: Collection parameter = tmpFIS.getParameter();
sascha@778:
tim@597: if(parameter != null){
tim@597: Iterator pit = parameter.iterator();
tim@597: while (pit.hasNext()){
tim@597: Parameter p = pit.next();
tim@597: Element parameterNode = creator.create("parameter");
tim@597: parameterNode.setAttribute(ATTRIBUTE_ID, p.getID());
tim@597: parameterNode.setAttribute(ATTRIBUTE_NAME, p.getName());
tim@597: fisNode.appendChild(parameterNode);
tim@597: }
tim@597: }
tim@597: factoriesNode.appendChild(fisNode);
tim@597: }
tim@597: }
tim@597: }
sascha@778:
tim@597: /**
tim@597: * Returns all FIS which Areas is intersected by this given Geometry
tim@597: * @param g the Geometry which should be used to determine the FIS.
tim@597: * @return all FIS which Areas is intersected by this given Geometry
ingo@792: * @throws MetaDataServiceException
tim@597: */
sascha@778: protected Collection getFIS(Geometry g)
tim@597: throws MetaDataServiceException{
tim@597: log.debug("MetaDataService.getFIS ==> Geometry");
tim@597: Collection resultValue = null;
tim@597: if (g != null){
tim@597: try {
tim@597: QueryExecutor queryExecutor = QueryExecutorFactory
tim@597: .getInstance()
tim@597: .getQueryExecutor();
tim@597: Collection result = queryExecutor.executeQuery(FIS_REGION_QUERY_ID,
tim@597: new String[]{g.toString()});
sascha@778:
tim@597: if (result != null){
tim@597: resultValue = new ArrayList(result.size());
tim@597: Iterator it = result.iterator();
tim@597: while (it.hasNext()){
tim@597: Result value = it.next();
tim@604: String fis_id = value.getString(0).trim();
tim@597: resultValue.add(new DefaultFIS(fis_id));
tim@597: }
tim@597: }
tim@597: } catch (QueryException e) {
tim@597: log.error(e,e);
tim@597: throw new MetaDataServiceException("Cannot Query FIS from DB.");
tim@597: }
tim@597: }
tim@597: return resultValue;
tim@597: }
sascha@778:
tim@597: /**
tim@597: * Returns all FIS which were represented by the given Mapservices
tim@597: * @param mapServices the Mapservices which should determine the FIS.
tim@597: * @return all FIS which where represented my the given Mapservices.
ingo@792: * @throws MetaDataServiceException
tim@597: */
tim@597: protected Collection getFIS(Collection mapServices)
tim@597: throws MetaDataServiceException{
tim@597: log.debug("MetaDataService.getFIS ==> MapServices");
tim@597: Collection resultValue = null;
tim@597: if (mapServices != null && !mapServices.isEmpty()){
tim@597: try {
sascha@778:
tim@597: String mapServiceNames = "";
sascha@778: Iterator mit = mapServices.iterator();
tim@597: while(mit.hasNext()){
tim@597: if (mapServiceNames.length() > 0){
tim@597: mapServiceNames += " , ";
tim@597: }
tim@604: mapServiceNames += "'"+mit.next().getID()+"'";
tim@597: }
sascha@778:
tim@597: QueryExecutor queryExecutor = QueryExecutorFactory
tim@597: .getInstance()
tim@597: .getQueryExecutor();
tim@597: Collection result = queryExecutor.executeQuery(
tim@597: MAPSERVICES_HAS_FIS_QUERY_ID,
tim@597: new String[]{mapServiceNames});
tim@597: if (result != null){
tim@597: resultValue = new ArrayList(result.size());
tim@597: Iterator it = result.iterator();
tim@597: while (it.hasNext()){
tim@597: Result value = it.next();
tim@606: String fisId = value.getString(0).trim();
tim@604: String mapServiceID = value.getString(1).trim();
sascha@778:
tim@597: // FIRST LOOK IF ONE MAPSERVICE REPRESENTS ONLY ONE PARAM
tim@604: Collection result2 = queryExecutor.executeQuery(
tim@604: MAPSERVICES_HAS_PARAMETER_QUERY_ID,
tim@604: new String[]{"'"+mapServiceID+"'"});
tim@597: Collection parameter = null;
tim@604: if (result2 != null && result2.size() == 1){
tim@604: Iterator it2 = result2.iterator();
tim@604: parameter = new ArrayList(1);
tim@604: while (it2.hasNext()){
tim@604: Result parameterValue = it2.next();
tim@604: String parameterID = parameterValue.getString(0)
tim@604: .trim();
sascha@778: parameter.add(new DefaultParameter(parameterID,
tim@604: parameterID));
tim@604: }
tim@604: }else{
tim@604: // IF FALSE LOOK IF THE GIVEN LAYERs TO AN MAPSERVICE
tim@604: // REPRESENTS DIFFERENT PARAMS
tim@604: MapService service = this.getMapService(mapServices,
tim@604: mapServiceID);
tim@604: Collection layer = service.getLayer();
tim@604: if (layer != null && !layer.isEmpty()){
sascha@778: String layerQueryString =
tim@604: this.createLayerQueryString(layer);
sascha@778: Collection parameterResult =
tim@604: queryExecutor.executeQuery(
tim@604: MAPSERVICES_HAS_PARAMETER_USING_LAYER_QUERY_ID,
tim@604: new String[]{"'"+mapServiceID+"'",
tim@604: layerQueryString});
sascha@778: if (parameterResult != null &&
tim@604: !parameterResult.isEmpty()){
tim@604: Iterator it2 = parameterResult.iterator();
tim@604: parameter = new ArrayList(parameterResult.size());
tim@604: while (it2.hasNext()){
tim@604: Result parameterValue = it2.next();
tim@604: String parameterID = parameterValue.getString(0)
tim@604: .trim();
sascha@778: parameter.add(new DefaultParameter(parameterID,
tim@604: parameterID));
tim@604: }
tim@604: }
tim@604: }
sascha@778:
tim@604: }
sascha@778:
tim@606: FIS fis = this.getFIS(resultValue, fisId);
tim@606: if (fis != null){
tim@606: if (parameter != null){
tim@606: fis.addParameter(parameter);
tim@606: }
tim@606: }else{
tim@606: resultValue.add(new DefaultFIS(fisId, parameter));
tim@606: }
tim@597: }
tim@597: }
tim@597: } catch (QueryException e) {
tim@597: log.error(e,e);
tim@597: throw new MetaDataServiceException("Cannot Query FIS from DB.");
tim@597: }
sascha@778:
tim@597: }
tim@597: return resultValue;
tim@597: }
sascha@778:
sascha@778:
tim@606: private FIS getFIS (Collection fis, String fisId){
sascha@778:
tim@606: Iterator it = fis.iterator();
tim@606: while(it.hasNext()){
tim@606: FIS tmpFIS = it.next();
tim@606: if (tmpFIS.getID().equals(fisId)){
tim@606: return tmpFIS;
tim@606: }
tim@606: }
tim@606: return null;
tim@606: }
sascha@778:
tim@604: private MapService getMapService(Collection mapServices,
tim@604: String mapServiceID){
tim@604: log.debug("MetaDataService.getMapService");
tim@604: Iterator it = mapServices.iterator();
tim@604: while (it.hasNext()){
tim@604: MapService service = it.next();
tim@604: if (service.getID().equals(mapServiceID)){
tim@604: return service;
tim@604: }
tim@604: }
tim@604: return null;
tim@604: }
sascha@778:
tim@604: private String createLayerQueryString(Collection layer){
tim@604: log.debug("MetaDataService.createLayerQueryString");
tim@604: StringBuffer sb = new StringBuffer();;
tim@604: Iterator it = layer.iterator();
tim@604: synchronized (sb) {
tim@604: while (it.hasNext()){
tim@604: Layer l = it.next();
tim@604: if (!l.isGroupLayer()){
tim@604: sb.append(l.getID());
tim@604: if (it.hasNext()){
tim@604: sb.append(" , ");
tim@604: }
tim@604: }
sascha@778:
tim@604: }
tim@604: }
tim@604: String returnValue = sb.toString();
tim@604: if (returnValue.endsWith(" , ")){
tim@604: returnValue = returnValue.substring(0,returnValue
tim@604: .lastIndexOf(","))
tim@604: .trim();
tim@604: }
tim@604: return returnValue;
tim@604: }
tim@597:
tim@597: @Override
tim@597: public void setup(ServiceFactory factory, Object globalContext) {
tim@597: log.debug("MetaDataService.setup");
tim@597: super.setup(factory, globalContext);
tim@597: // TODO: Perhaps it is necessary to init the QueryIds here.
tim@597: }
tim@597:
tim@597: }