nl.b3p.viewer.stripes.CatalogSearchActionBean.java Source code

Java tutorial

Introduction

Here is the source code for nl.b3p.viewer.stripes.CatalogSearchActionBean.java

Source

/*
 * Copyright (C) 2012-2013 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package nl.b3p.viewer.stripes;

import java.io.IOException;
import java.io.StringReader;
import java.math.BigInteger;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.xml.bind.JAXBException;
import net.sourceforge.stripes.action.*;
import net.sourceforge.stripes.validation.Validate;
import nl.b3p.csw.client.CswClient;
import static nl.b3p.csw.client.CswRequestCreator.createCswRequest;
import static nl.b3p.csw.client.CswRequestCreator.createPropertyName;
import static nl.b3p.csw.client.CswRequestCreator.createQueryString;
import nl.b3p.csw.client.FilterCreator;
import nl.b3p.csw.client.InputBySearch;
import nl.b3p.csw.client.OutputBySearch;
import nl.b3p.csw.client.OwsException;
import nl.b3p.csw.jaxb.csw.GetRecords;
import nl.b3p.csw.jaxb.filter.And;
import nl.b3p.csw.jaxb.filter.BinaryLogicOpType;
import nl.b3p.csw.jaxb.filter.FilterType;
import nl.b3p.csw.jaxb.filter.Or;
import nl.b3p.csw.jaxb.filter.PropertyIsEqualTo;
import nl.b3p.csw.jaxb.filter.PropertyIsLike;
import nl.b3p.csw.jaxb.filter.SortBy;
import nl.b3p.csw.server.CswServable;
import nl.b3p.csw.server.GeoNetworkCswServer;
import nl.b3p.csw.util.OnlineResource;
import nl.b3p.csw.util.Protocol;
import nl.b3p.viewer.config.app.Application;
import nl.b3p.viewer.config.app.ApplicationLayer;
import nl.b3p.viewer.config.app.Level;
import nl.b3p.viewer.config.services.GeoService;
import nl.b3p.viewer.config.services.Layer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.nl.DutchAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.util.Version;
import org.jdom.Element;
import org.jdom.JDOMException;

import org.json.*;
import org.stripesstuff.stripersist.Stripersist;

/**
 *
 * @author Matthijs Laan
 * @author Meine Toonen
 */
@UrlBinding("/action/csw/search")
@StrictBinding
public class CatalogSearchActionBean implements ActionBean {

    private ActionBeanContext context;
    private static final Log log = LogFactory.getLog(CatalogSearchActionBean.class);
    private static final String defaultWildCard = "*";

    private BigInteger maxRecords = new BigInteger("1000");

    @Validate
    private String url;

    @Validate
    private String q;

    @Validate
    private String advancedString;

    @Validate
    private String advancedProperty;

    @Validate
    private Application application;

    //<editor-fold defaultstate="collapsed" desc="getters and setters">
    public ActionBeanContext getContext() {
        return context;
    }

    public void setContext(ActionBeanContext context) {
        this.context = context;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getQ() {
        return q;
    }

    public void setQ(String q) {
        this.q = q;
    }

    public String getAdvancedString() {
        return advancedString;
    }

    public void setAdvancedString(String advancedString) {
        this.advancedString = advancedString;
    }

    public String getAdvancedProperty() {
        return advancedProperty;
    }

    public void setAdvancedProperty(String advancedProperty) {
        this.advancedProperty = advancedProperty;
    }

    public Application getApplication() {
        return application;
    }

    public void setApplication(Application application) {
        this.application = application;
    }

    //</editor-fold>        

    @DefaultHandler
    public Resolution search() throws JSONException {
        JSONObject json = new JSONObject();
        json.put("success", Boolean.FALSE);
        String error = null;

        try {
            CswServable server = new GeoNetworkCswServer(null, url, null, null);

            CswClient client = new CswClient(server);
            InputBySearch input = new InputBySearch(q);
            OutputBySearch output = client.search(input);

            List<OnlineResource> map = output.getResourcesFlattened();
            JSONArray results = getResults(map, output);

            json.put("results", results);

            json.put("success", Boolean.TRUE);
        } catch (Exception e) {

            error = "Fout bij zoeken in CSW: " + e.toString();
            log.error("Fout bij zoeken in csw:", e);
            if (e.getCause() != null) {
                error += "; oorzaak: " + e.getCause().toString();
            }
        }

        if (error != null) {
            json.put("error", error);
        }

        return new StreamingResolution("application/json", new StringReader(json.toString(4)));
    }

    public Resolution advancedSearch() throws JSONException {
        JSONObject json = new JSONObject();
        json.put("success", Boolean.FALSE);
        CswServable server = new GeoNetworkCswServer(null, url, null, null);
        CswClient client = new CswClient(server);
        try {
            OutputBySearch output = client.search(new InputBySearch(
                    createAdvancedCswRequest(q, advancedString, advancedProperty, null, maxRecords, null)));
            List<Element> els = output.getSearchResults();
            List<Protocol> prots = new ArrayList();
            prots.add(Protocol.WMS);
            List<OnlineResource> list = new ArrayList();
            for (Iterator<Element> it = els.iterator(); it.hasNext();) {
                Element element = it.next();
                Map<URI, List<OnlineResource>> orMap = output.getResourcesMap(element, prots);
                Set<URI> uris = orMap.keySet();
                for (Iterator<URI> uriIt = uris.iterator(); uriIt.hasNext();) {
                    URI uri = uriIt.next();
                    List<OnlineResource> orList = orMap.get(uri);
                    list.addAll(orList);
                }
            }
            Map<Layer, String> descriptionsByLayer = new HashMap();
            List<Layer> layers = getLayers(list, descriptionsByLayer, output);

            Map<ApplicationLayer, String> descriptionsByApplayer = new HashMap();
            List<ApplicationLayer> appLayers = getAppLayers(layers, descriptionsByApplayer, descriptionsByLayer);

            Map<Level, String> descriptionsByLevel = new HashMap();
            List<Level> levels = getLevels(appLayers, descriptionsByApplayer, descriptionsByLevel);

            JSONArray found = new JSONArray();
            for (Level level : levels) {
                JSONObject obj = level.toJSONObject(false, application, context.getRequest());
                found.put(obj);
            }
            List<Level> children = application.getRoot().getChildren();
            JSONArray childs = new JSONArray();
            for (Level child : children) {
                childs.put(child.toJSONObject(false, application, context.getRequest()));
            }

            Set<Level> levelDesc = descriptionsByLevel.keySet();
            JSONObject descriptions = new JSONObject();
            for (Iterator<Level> LevelIterator = levelDesc.iterator(); LevelIterator.hasNext();) {
                Level level = LevelIterator.next();
                JSONObject obj = new JSONObject();
                obj.put("level", level.getId());
                obj.put("description", descriptionsByLevel.get(level));
                descriptions.put("" + level.getId(), obj);
            }
            JSONObject results = new JSONObject();
            results.put("found", found);
            results.put("children", childs);
            results.put("descriptions", descriptions);
            json.put("results", results);
            json.put("success", Boolean.TRUE);
        } catch (IOException ex) {
            log.error("Fout bij zoeken in csw:", ex);
        } catch (JDOMException ex) {
            log.error("Fout bij zoeken in csw:", ex);
        } catch (JAXBException ex) {
            log.error("Fout bij zoeken in csw:", ex);
        } catch (OwsException ex) {
            log.error("Fout bij zoeken in csw:", ex);
        }

        return new StreamingResolution("application/json", new StringReader(json.toString(4)));
    }

    private List<Level> getLevels(List<ApplicationLayer> appLayers,
            Map<ApplicationLayer, String> descriptionsByApplayer, Map<Level, String> descriptionsByLevel) {
        List<Level> foundLevels = new ArrayList();
        Level root = application.getRoot();
        for (ApplicationLayer applicationLayer : appLayers) {
            Level l = root.getParentInSubtree(applicationLayer);
            if (l != null) {
                foundLevels.add(l);
                if (descriptionsByApplayer.containsKey(applicationLayer)) {
                    descriptionsByLevel.put(l, descriptionsByApplayer.get(applicationLayer));
                }
            }
        }
        return foundLevels;
    }

    private List<ApplicationLayer> getAppLayers(List<Layer> layers,
            Map<ApplicationLayer, String> descriptionsByApplayer, Map<Layer, String> descriptionsByLayer) {
        EntityManager em = Stripersist.getEntityManager();
        List<ApplicationLayer> foundAppLayers = new ArrayList();
        Level root = application.getRoot();
        for (Layer layer : layers) {
            List<ApplicationLayer> appLayers = em
                    .createQuery("FROM ApplicationLayer WHERE service = :geoservice and layerName = :name",
                            ApplicationLayer.class)
                    .setParameter("geoservice", layer.getService()).setParameter("name", layer.getName())
                    .getResultList();
            for (ApplicationLayer applicationLayer : appLayers) {
                if (root.containsLayerInSubtree(applicationLayer)) {
                    foundAppLayers.add(applicationLayer);
                    if (descriptionsByLayer.containsKey(layer)) {
                        descriptionsByApplayer.put(applicationLayer, descriptionsByLayer.get(layer));
                    }
                }

            }
        }
        return foundAppLayers;
    }

    private List<Layer> getLayers(List<OnlineResource> lijst, Map<Layer, String> descriptions,
            OutputBySearch output) {
        EntityManager em = Stripersist.getEntityManager();
        List<Layer> foundLayers = new ArrayList();
        for (OnlineResource resource : lijst) {
            String rurl = resource.getUrl() != null ? resource.getUrl().toString() : null;
            String layerName = resource.getName();
            String protocol = resource.getProtocol() != null ? resource.getProtocol().getName() : null;

            if (rurl != null && protocol != null) {
                if (protocol.toLowerCase().indexOf("wms") != -1) {
                    List<GeoService> foundServices = em
                            .createQuery("FROM GeoService WHERE url = :url", GeoService.class)
                            .setParameter("url", rurl).getResultList();
                    for (GeoService geoService : foundServices) {
                        List<Layer> layers = geoService.loadLayerTree();
                        for (Layer layer : layers) {
                            if (!layer.isVirtual()) {
                                if (layer.getName().equalsIgnoreCase(layerName)) {
                                    try {
                                        String abstractText = output.getAbstractText(resource.getMetadata());
                                        descriptions.put(layer, abstractText);

                                    } catch (JDOMException ex) {
                                    }

                                    foundLayers.add(layer);
                                }
                            }
                        }
                    }
                }
            }
        }
        return foundLayers;
    }

    private JSONArray getResults(List<OnlineResource> resourceList, OutputBySearch output)
            throws JDOMException, JSONException {
        JSONArray results = new JSONArray();
        for (OnlineResource resource : resourceList) {

            String title = output.getTitle(resource.getMetadata());
            String rurl = resource.getUrl() != null ? resource.getUrl().toString() : null;
            String layer = resource.getName();
            String protocol = resource.getProtocol() != null ? resource.getProtocol().getName() : null;

            if (title != null && rurl != null && protocol != null) {
                if (protocol.toLowerCase().indexOf("wms") != -1) {
                    JSONObject result = new JSONObject();
                    result.put("label", title + (layer != null ? " (laag: " + layer + ")" : ""));
                    result.put("url", rurl);
                    result.put("protocol", "wms");
                    results.put(result);
                }
            }
        }
        return results;
    }

    private static GetRecords createAdvancedCswRequest(String queryString, String advancedValue,
            String propertyName, BigInteger startPosition, BigInteger maxRecords, SortBy sortBy)
            throws IOException {

        FilterType filterType = new FilterType();
        boolean emptySearchStrings = true;

        List andList = new ArrayList();
        Or queryOr = null;
        Or typeringOr = null;

        if (queryString != null) {
            emptySearchStrings = false;
            queryOr = createOrFilter(queryString, null);
            andList.add(queryOr);
        }
        if (advancedValue != null) {
            emptySearchStrings = false;

            PropertyIsEqualTo propertyIsEqualTo = FilterCreator.createPropertyIsEqualTo(advancedValue,
                    propertyName);
            List orList = new ArrayList();
            orList.add(propertyIsEqualTo);
            typeringOr = new Or(new BinaryLogicOpType(orList));

            andList.add(propertyIsEqualTo);
        }

        if (emptySearchStrings) {
            return createCswRequest("*", propertyName, startPosition, maxRecords, sortBy, null, null, null);
        }

        And and = new And(new BinaryLogicOpType(andList));

        if (queryOr != null && typeringOr != null) {
            filterType.setLogicOps(and);
        } else if (queryOr != null) {
            filterType.setLogicOps(queryOr);
        } else if (typeringOr != null) {
            filterType.setLogicOps(typeringOr);
        }

        return createCswRequest(filterType, startPosition, maxRecords, sortBy);
    }

    private static Or createOrFilter(String queryString, String propertyName) {
        List orList = new ArrayList();
        queryString = createQueryString(queryString, false);
        if (queryString != null && !queryString.trim().equals(defaultWildCard)) {

            propertyName = createPropertyName(propertyName);

            PropertyIsEqualTo propertyIsEqualTo = FilterCreator.createPropertyIsEqualTo(queryString, propertyName);

            StandardAnalyzer standardAnalyzer = new StandardAnalyzer(Version.LUCENE_45,
                    DutchAnalyzer.getDefaultStopSet());

            orList.add(propertyIsEqualTo);
            try {

                TokenStream tokenStream = standardAnalyzer.tokenStream("", queryString);
                OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
                CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);

                tokenStream.reset();
                while (tokenStream.incrementToken()) {
                    int startOffset = offsetAttribute.startOffset();
                    int endOffset = offsetAttribute.endOffset();
                    String term = charTermAttribute.toString();
                    PropertyIsLike propertyIsLike = FilterCreator.createPropertyIsLike(term, propertyName);
                    orList.add(propertyIsLike);
                }
                tokenStream.close();
            } catch (IOException e) {
                PropertyIsLike propertyIsLike = FilterCreator.createPropertyIsLike(queryString, propertyName);
                orList.add(propertyIsLike);
            }
        }

        Or or = new Or(new BinaryLogicOpType(orList));

        return or;
    }
}