view gnv-artifacts/src/main/java/de/intevation/gnv/artifacts/services/MetaDataService.java @ 605:e8ebdbc7f1e3

First step of removing the cache blob. The static part of the describe document will be created by using the input data stored at each state. Some TODOs left (see ChangeLog). gnv-artifacts/trunk@671 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 09 Feb 2010 14:27:55 +0000
parents 938ce81a6bd0
children 9efc1c256dbb
line wrap: on
line source
/**
 *
 */
package de.intevation.gnv.artifacts.services;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.xml.xpath.XPathConstants;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;

import de.intevation.artifactdatabase.DefaultService;
import de.intevation.artifactdatabase.XMLUtils;
import de.intevation.artifacts.ArtifactNamespaceContext;
import de.intevation.artifacts.CallMeta;
import de.intevation.artifacts.ServiceFactory;
import de.intevation.gnv.artifacts.services.requestobjects.DefaultFIS;
import de.intevation.gnv.artifacts.services.requestobjects.DefaultLayer;
import de.intevation.gnv.artifacts.services.requestobjects.DefaultMapService;
import de.intevation.gnv.artifacts.services.requestobjects.DefaultParameter;
import de.intevation.gnv.artifacts.services.requestobjects.FIS;
import de.intevation.gnv.artifacts.services.requestobjects.Layer;
import de.intevation.gnv.artifacts.services.requestobjects.MapService;
import de.intevation.gnv.artifacts.services.requestobjects.Parameter;
import de.intevation.gnv.geobackend.base.Result;
import de.intevation.gnv.geobackend.base.query.QueryExecutor;
import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
import de.intevation.gnv.geobackend.base.query.exception.QueryException;
import de.intevation.gnv.utils.ArtifactXMLUtilities;

/**
 * @author Tim Englich <tim.englich@intevation.de>
 *
 */
public class MetaDataService extends DefaultService {

    /**
     * the logger, used to log exceptions and additionally information
     */
    private static Logger log = Logger.getLogger(MetaDataService.class);

    
    private final static String FIS_REGION_QUERY_ID = 
                                      "mapviewer_interface_fis_region";
    private final static String MAPSERVICES_HAS_FIS_QUERY_ID = 
                                      "mapviewer_interface_mapservices_has_fis";
    private final static String MAPSERVICES_HAS_PARAMETER_QUERY_ID = 
                                "mapviewer_interface_mapservices_has_parameter";
    
    private final static String MAPSERVICES_HAS_PARAMETER_USING_LAYER_QUERY_ID = 
        "mapviewer_interface_mapservices_has_parameter_using_layer";
    
    private static String ATTRIBUTE_ID = "id";
    private static String ATTRIBUTE_NAME = "name";
    private static String ATTRIBUTE_TYPE = "type";
    private static String ATTRIBUTE_URL = "url";
    private static String ATTRIBUTE_GROUPLAYER = "isgrouplayer";
    private static String ATTRIBUTE_PARENTID = "parentid";
    private static String ATTRIBUTE_SRS = "srs";
    
    
    private static String XPATH_LOACTION_NODE = "art:GetMetaData/art:location";
    private static String XPATH_MAPSERVICES_NODESET = "art:GetMetaData/" +
                                                      "art:mapservices/" +
                                                      "art:mapservice";
    private static String XPATH_LAYER_NODESET = "art:layer";
    
    /**
     * The UID of this Class.
     */
    private static final long serialVersionUID = -8446483887497236372L;

    /**
     * Constructor
     */
    public MetaDataService() {
        super();
    }

    /**
     * @see de.intevation.artifactdatabase.DefaultService#process(org.w3c.dom.Document, java.lang.Object, de.intevation.artifacts.CallMeta)
     */
    @Override
    public Document process(Document data, Object globalContext,
                            CallMeta callMeta) {
        log.debug("MetaDataService.process");
        Document document = null;
        try {
            Geometry g = this.parseGeometry(data);
            Collection<MapService> mapServices = this.parseMapServices(data);
            Collection<FIS> resultFIS = this.unionFIS(this.getFIS(g), 
                                                      this.getFIS(mapServices));
            document = XMLUtils.newDocument();
            this.writeFIS2Document(document, resultFIS);
            log.debug(new ArtifactXMLUtilities().writeDocument2String(document));
        } catch (MetaDataServiceException e) {
            log.error(e,e);
            document = new ArtifactXMLUtilities()
                          .createExceptionReport(e.getMessage(), document);
        }
        return document;
    }
    
    private Geometry parseGeometry(Document data) 
                                   throws MetaDataServiceException{
        log.debug("MetaDataService.parseGeometry");
        
        Element locationNode = (Element) XMLUtils.xpath(
                data,
                XPATH_LOACTION_NODE,
                XPathConstants.NODE,
                ArtifactNamespaceContext.INSTANCE
            );
        Geometry returnValue = null;
        if (locationNode != null) {
            String srs = locationNode.getAttribute(ATTRIBUTE_SRS);
            // TODO: use SRS to transform the Geometry to target-System.
            String geometryValue = locationNode.getTextContent();
            if (geometryValue != null){
                try {
                    returnValue = new WKTReader().read(geometryValue);
                } catch (ParseException e) {
                    log.error(e,e);
                    throw new MetaDataServiceException("The given Geometry" +
                                                       "String is not a " +
                                                       "valid WKT.");
                }
            }
        }
        return returnValue;
    }
    
    private Collection<MapService> parseMapServices(Document data){
        log.debug("MetaDataService.parseMapServices");
        
        NodeList mapServices = (NodeList) XMLUtils.xpath(data, 
                                             XPATH_MAPSERVICES_NODESET,
                                             XPathConstants.NODESET,
                                             ArtifactNamespaceContext.INSTANCE);
        Collection<MapService> returnValue = null;
        if (mapServices != null){
            returnValue = new ArrayList<MapService>(mapServices.getLength());
            for (int i = 0; i < mapServices.getLength(); i++){
                Element mapServiceNode = (Element)mapServices.item(i);
                String id = mapServiceNode.getAttribute(ATTRIBUTE_ID);
                String type = mapServiceNode.getAttribute(ATTRIBUTE_TYPE);
                String url = mapServiceNode.getAttribute(ATTRIBUTE_URL);
                Collection<Layer> layer = null;
                
                NodeList layerNodes = (NodeList) XMLUtils.xpath(mapServiceNode, 
                                            XPATH_LAYER_NODESET,
                                            XPathConstants.NODESET,
                                            ArtifactNamespaceContext.INSTANCE);
                if (layerNodes != null){
                    layer = new ArrayList<Layer>(layerNodes.getLength());
                    for (int j = 0; j < layerNodes.getLength(); j++){
                        Element layerNode = (Element)layerNodes.item(j);
                        String layerId = layerNode.getAttribute(ATTRIBUTE_ID);
                        String layerName = layerNode.getAttribute(ATTRIBUTE_NAME);
                        boolean isGroupLayer = 
                                      Boolean.parseBoolean(layerNode
                                                      .getAttribute(
                                                         ATTRIBUTE_GROUPLAYER));
                        String parentId = layerNode
                                              .getAttribute(ATTRIBUTE_PARENTID);
                        
                        layer.add(new DefaultLayer(layerId,
                                                   layerName,
                                                   isGroupLayer,
                                                   parentId));
                    }
                }
                MapService mapService = new DefaultMapService(id, layer, 
                                                              type, url);
                returnValue.add(mapService);
                
            }
        }
        return returnValue;
    }
    
    private Collection<FIS> unionFIS(Collection<FIS> fromGeometry, 
                                        Collection<FIS> fromMapservices){
        log.debug("MetaDataService.unionFIS");
        Collection<FIS> returnValue = null;
        if (fromGeometry == null || fromGeometry.isEmpty()){
            returnValue = fromMapservices;
        }else if (fromMapservices == null || fromMapservices.isEmpty()){
            returnValue = fromGeometry;
        }else{
            
            returnValue = new ArrayList<FIS>();
            Iterator<FIS> it = fromMapservices.iterator();
            while (it.hasNext()){
                FIS fis = it.next();
                if (fromGeometry.contains(fis)){
                    returnValue.add(fis);
                }
            }
        }
        return returnValue;
    }
    
    /**
     * Puts the retrieved FIS into the given XML-Document.
     * @param document the Document where the FIS should be put in.
     * @param fis the retrieved FIS which should be written into 
     *            the XML-Document.
     */
    private void writeFIS2Document(Document document, Collection<FIS> fis){
        
        if (fis != null){
            Iterator<FIS> it = fis.iterator();
            XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
                    document,
                    ArtifactNamespaceContext.NAMESPACE_URI,
                    ArtifactNamespaceContext.NAMESPACE_PREFIX
                );
            Node rootNode = creator.create("result");
            document.appendChild(rootNode);
            
            Node factoriesNode = creator.create("factories");
            rootNode.appendChild(factoriesNode);
            while (it.hasNext()){
                FIS tmpFIS = it.next();
                Element fisNode = creator.create("factory");
                fisNode.setAttribute("art:name",tmpFIS.getID());
                
                Collection<Parameter> parameter = tmpFIS.getParameter();
                
                if(parameter != null){
                    Iterator<Parameter> pit = parameter.iterator();
                    while (pit.hasNext()){
                        Parameter p = pit.next();
                        Element parameterNode = creator.create("parameter");
                        parameterNode.setAttribute(ATTRIBUTE_ID, p.getID());
                        parameterNode.setAttribute(ATTRIBUTE_NAME, p.getName());
                        fisNode.appendChild(parameterNode);
                    }
                }
                factoriesNode.appendChild(fisNode);
            }
        }
    }
    
    /**
     * Returns all FIS which Areas is intersected by this given Geometry
     * @param g the Geometry which should be used to determine the FIS.
     * @return all FIS which Areas is intersected by this given Geometry
     */
    protected Collection<FIS> getFIS(Geometry g) 
                                        throws MetaDataServiceException{
        log.debug("MetaDataService.getFIS ==> Geometry");
        Collection<FIS> resultValue = null;
        if (g != null){
            try {
                QueryExecutor queryExecutor = QueryExecutorFactory
                                               .getInstance()
                                               .getQueryExecutor();
                Collection<Result> result = queryExecutor.executeQuery(FIS_REGION_QUERY_ID,
                                                    new String[]{g.toString()});
                
                if (result != null){
                    resultValue = new ArrayList<FIS>(result.size());
                    Iterator<Result> it = result.iterator();
                    while (it.hasNext()){
                        Result value = it.next();
                        String fis_id = value.getString(0).trim();
                        resultValue.add(new DefaultFIS(fis_id));
                    }
                }
            } catch (QueryException e) {
                log.error(e,e);
                throw new MetaDataServiceException("Cannot Query FIS from DB.");
            }
        }
        return resultValue;
    }
    
    /**
     * Returns all FIS which were represented by the given Mapservices
     * @param mapServices the Mapservices which should determine the FIS.
     * @return all FIS which where represented my the given Mapservices.
     */
    protected Collection<FIS> getFIS(Collection<MapService> mapServices)
                                              throws MetaDataServiceException{
        log.debug("MetaDataService.getFIS ==> MapServices");
        Collection<FIS> resultValue = null;
        if (mapServices != null && !mapServices.isEmpty()){
            try {
                
                String mapServiceNames = "";
                Iterator<MapService> mit = mapServices.iterator(); 
                while(mit.hasNext()){
                    if (mapServiceNames.length() > 0){
                        mapServiceNames += " , ";
                    }
                    mapServiceNames += "'"+mit.next().getID()+"'";
                }
                
                QueryExecutor queryExecutor = QueryExecutorFactory
                                               .getInstance()
                                               .getQueryExecutor();
                Collection<Result> result = queryExecutor.executeQuery(
                                                  MAPSERVICES_HAS_FIS_QUERY_ID,
                                                  new String[]{mapServiceNames});
                if (result != null){
                    resultValue = new ArrayList<FIS>(result.size());
                    Iterator<Result> it = result.iterator();
                    while (it.hasNext()){
                        Result value = it.next();
                        String fis_id = value.getString(0).trim();
                        String mapServiceID = value.getString(1).trim();
                       
                        // FIRST LOOK IF ONE MAPSERVICE REPRESENTS ONLY ONE PARAM
                        Collection<Result> result2 = queryExecutor.executeQuery(
                                MAPSERVICES_HAS_PARAMETER_QUERY_ID,
                                new String[]{"'"+mapServiceID+"'"});
                        Collection<Parameter> parameter = null;
                        if (result2 != null && result2.size() == 1){
                            Iterator<Result> it2 = result2.iterator();
                            parameter = new ArrayList<Parameter>(1);
                            while (it2.hasNext()){
                                Result parameterValue = it2.next();
                                String parameterID = parameterValue.getString(0)
                                                                   .trim();
                                parameter.add(new DefaultParameter(parameterID, 
                                                                   parameterID));
                            }
                        }else{
                            // IF FALSE LOOK IF THE GIVEN LAYERs TO AN MAPSERVICE
                            // REPRESENTS DIFFERENT PARAMS
                            MapService service = this.getMapService(mapServices,
                                                                    mapServiceID);
                            Collection<Layer> layer = service.getLayer();
                            if (layer != null && !layer.isEmpty()){
                                String layerQueryString = 
                                    this.createLayerQueryString(layer);
                                Collection<Result> parameterResult = 
                                    queryExecutor.executeQuery(
                                        MAPSERVICES_HAS_PARAMETER_USING_LAYER_QUERY_ID,
                                        new String[]{"'"+mapServiceID+"'",
                                                     layerQueryString});
                                if (parameterResult != null && 
                                    !parameterResult.isEmpty()){
                                    Iterator<Result> it2 = parameterResult.iterator();
                                    parameter = new ArrayList<Parameter>(parameterResult.size());
                                    while (it2.hasNext()){
                                        Result parameterValue = it2.next();
                                        String parameterID = parameterValue.getString(0)
                                                                           .trim();
                                        parameter.add(new DefaultParameter(parameterID, 
                                                                           parameterID));
                                    }
                                }
                            }
                            
                        }
                        resultValue.add(new DefaultFIS(fis_id, parameter));
                    }
                }
            } catch (QueryException e) {
                log.error(e,e);
                throw new MetaDataServiceException("Cannot Query FIS from DB.");
            }
           
        }
        return resultValue;
    }
    
    
    private MapService getMapService(Collection<MapService> mapServices,
                                     String mapServiceID){
        log.debug("MetaDataService.getMapService");
        Iterator<MapService> it = mapServices.iterator();
        while (it.hasNext()){
            MapService service = it.next();
            if (service.getID().equals(mapServiceID)){
                return service;
            }
        }
        return null;
    }
    
    private String createLayerQueryString(Collection<Layer> layer){
        log.debug("MetaDataService.createLayerQueryString");
        StringBuffer sb = new StringBuffer();;
        Iterator<Layer> it = layer.iterator();
        synchronized (sb) {
            while (it.hasNext()){
                Layer l = it.next();
                if (!l.isGroupLayer()){
                    sb.append(l.getID());
                    if (it.hasNext()){
                        sb.append(" , ");
                    }
                }
                
            }
        }
        String returnValue = sb.toString();
        if (returnValue.endsWith(" , ")){
            returnValue = returnValue.substring(0,returnValue
                                                  .lastIndexOf(","))
                                                  .trim();
        }
        return returnValue;
    }

    /**
     * @see de.intevation.artifactdatabase.DefaultService#setup(de.intevation.artifacts.ServiceFactory, java.lang.Object)
     */
    @Override
    public void setup(ServiceFactory factory, Object globalContext) {
        log.debug("MetaDataService.setup");
        super.setup(factory, globalContext);
        // TODO: Perhaps it is necessary to init the QueryIds here.
    }

}

http://dive4elements.wald.intevation.org