com.noterik.bart.fs.action.CollectionIndexAction.java Source code

Java tutorial

Introduction

Here is the source code for com.noterik.bart.fs.action.CollectionIndexAction.java

Source

/* 
* CollectionIndexAction.java
* 
* Copyright (c) 2012 Noterik B.V.
* 
* This file is part of smithers, related to the Noterik Springfield project.
*
* Smithers 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.
*
* Smithers 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 Smithers.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.noterik.bart.fs.action;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;

import com.noterik.bart.fs.fsxml.FSXMLRequestHandler;
import com.noterik.springfield.tools.fs.URIParser;

public class CollectionIndexAction extends ActionAdapter {

    private static final long serialVersionUID = 1L;
    private static Logger logger = Logger.getLogger(CollectionIndexAction.class);
    private static final String QUEUE_URI = "/domain/{domainid}/service/smithers/queue/collectionindex/job";
    private static final String CONFIG_URI = "/domain/{domainid}/user/{user}/config/collectionindex";
    private static final String DEFAULT_INDEX_TYPE = "item";
    private static final String DEFAULT_INDEX_URI = "/domain/{domainid}/user/{user}/index/collectionindex";

    private String domainid;
    private String userid;
    private String indexUri;
    private String indexType;
    private String indexSaveType = null;

    Document typeDocument = DocumentHelper.createDocument();

    /* To avoid too many requests keep user configs in memory */
    private Map<String, Map<String, String>> userConfigMemory;

    public String run() {
        new Thread() {
            @Override
            public void run() {
                logger.debug("run collectionindex");
                String eventUri = event.getUri();
                logger.debug("eventUri = " + eventUri);
                domainid = URIParser.getDomainFromUri(eventUri);
                String collectionUri = getSubUri(eventUri, 6) + "/";
                handle(collectionUri);
            }
        }.start();
        return null;
    }

    private void handle(String collectionUri) {
        userid = URIParser.getUserFromUri(collectionUri);
        logger.debug("collectionuri = " + collectionUri + " load config");
        loadIndexConfig();

        logger.debug("check if " + indexUri + " has childs of type " + indexSaveType);

        if (!FSXMLRequestHandler.instance().hasChildren(indexUri, indexSaveType)) {
            createCollectionIndex(collectionUri);
        } else {
            updateCollectionIndex(collectionUri);
        }
    }

    // load user configuration what field are needed for the index
    private void loadIndexConfig() {
        if (userConfigMemory == null) {
            userConfigMemory = new HashMap<String, Map<String, String>>();
        }
        if (!userConfigMemory.containsKey(domainid + ":" + userid)) {
            logger.debug("config not yet in memory for " + domainid + " " + userid);
            Map<String, String> propertiesMap = new HashMap<String, String>();

            String configUri = CONFIG_URI.replace("{domainid}", domainid).replace("{user}", userid);
            Document configuration = FSXMLRequestHandler.instance().getNodeProperties(configUri, false);

            if (configuration != null) {
                logger.debug("configuration " + configuration.asXML());

                List<Node> properties = configuration.selectNodes("//properties/*");
                for (Iterator<Node> i = properties.iterator(); i.hasNext();) {
                    Element property = (Element) i.next();
                    if (property.getName().equals("indextype")) {
                        indexType = property.getText();
                    } else if (property.getName().equals("indexuri")) {
                        indexUri = property.getText().replace("{domainid}", domainid).replace("{user}", userid);
                    } else if (property.getName().equals("indexsavetype")) {
                        indexSaveType = property.getText();
                    } else {
                        propertiesMap.put(property.getName(), "enabled");
                    }
                }
            } else {
                logger.debug("get default config variables");
                //default indextype & uri when configuration is not available
                indexType = DEFAULT_INDEX_TYPE;
                indexSaveType = DEFAULT_INDEX_TYPE;
                indexUri = DEFAULT_INDEX_URI.replace("{domainid}", domainid).replace("{user}", userid);
            }
            if (indexSaveType == null) {
                indexSaveType = indexType;
            }
            userConfigMemory.put(domainid + ":" + userid, propertiesMap);
        } else {
            logger.debug("config found in memory for " + domainid + ":" + userid);
        }
    }

    private void updateCollectionIndex(String collectionUri) {
        Map<String, Object> collectionDetails = getCollectionDetails(collectionUri);

        deleteTypes(collectionUri);

        if (collectionDetails != null) {
            loopTypes(collectionUri, collectionDetails);
        }
    }

    private void createCollectionIndex(String uri) {
        logger.debug("create index");
        createIndex();

        String collectionUri = getSubUri(uri, 5);
        int numCollections = getNumberOfCollections(collectionUri);

        logger.debug("loop over all collections = " + numCollections);
        /* Loop over all collections */
        for (int i = 0; i < numCollections; i++) {
            Document collection = FSXMLRequestHandler.instance().getNodePropertiesByType(collectionUri, 10, i, 1);
            Map<String, Object> collectionDetails = getCollectionDetails(collection, collectionUri);

            if (collectionDetails != null) {
                loopTypes(collectionUri, collectionDetails);
            }
        }
    }

    private void makeTypeFromCollection(Map<String, Object> collectionDetails) {
        typeDocument.clearContent();
        Element fsxml = typeDocument.addElement("fsxml");
        Element type = fsxml.addElement(indexSaveType);

        //add refer to original collection
        Element referCollectionPresentation = type.addElement("collectionrefer");
        referCollectionPresentation.addAttribute("id", "1");
        referCollectionPresentation.addAttribute("referid", (String) collectionDetails.get("collectionUri"));

        Element properties = type.addElement("properties");
        //add standard properties
        properties.addElement("collection").addText((String) collectionDetails.get("collectionUri"));

        //add user configured properties
        Map<String, String> items = userConfigMemory.get(domainid + ":" + userid);

        for (String item : items.keySet()) {
            if (item.equals("collectiontitle") || item.equals("collectiondescription")
                    || item.equals("collectionstatus")) {
                properties.addElement(item).addText((String) collectionDetails.get(item));
            }
        }

        long timestamp = new Date().getTime();
        type.addAttribute("id", String.valueOf(timestamp));

        // Add directly to fs so maggie get's updated with first content faster
        FSXMLRequestHandler.instance().saveFsXml(indexUri, typeDocument.asXML(), "PUT", true);
    }

    private void makeType(Element typeContent, Map<String, Object> collectionDetails) {
        // create new type
        typeDocument.clearContent();
        Element fsxml = typeDocument.addElement("fsxml");
        Element type = fsxml.addElement(indexSaveType);

        // add refer to original collection
        Element referCollectionPresentation = type.addElement("collectionrefer");
        referCollectionPresentation.addAttribute("id", "1");
        referCollectionPresentation.addAttribute("referid", (String) collectionDetails.get("collectionUri"));

        Element properties = type.addElement("properties");
        //add standard properties
        properties.addElement("collection").addText((String) collectionDetails.get("collectionUri"));

        //add user configured properties
        Map<String, String> items = userConfigMemory.get(domainid + ":" + userid);

        for (String item : items.keySet()) {
            if (item.equals("collectiontitle") || item.equals("collectiondescription")
                    || item.equals("collectionstatus")) {
                properties.addElement(item).addText((String) collectionDetails.get(item));
            }
        }
        long timestamp = new Date().getTime();
        type.addAttribute("id", String.valueOf(timestamp));

        logger.debug("about to PUT to uri " + indexUri + " this xml: " + typeDocument.asXML());

        // Add directly to fs so maggie get's updated with first content faster
        FSXMLRequestHandler.instance().saveFsXml(indexUri, typeDocument.asXML(), "PUT", true);
    }

    // Get a sub part of the uri
    private String getSubUri(String uri, int length) {
        if (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        if (uri.endsWith("/")) {
            uri = uri.substring(0, uri.length() - 1);
        }

        String[] parts = uri.split("/");
        if (parts.length < length) {
            return uri;
        }

        String subUri = "/";
        for (int i = 0; i < length; i++) {
            subUri += parts[i] + "/";
        }
        return subUri.substring(0, subUri.length() - 1);
    }

    //Collection details
    private Map<String, Object> getCollectionDetails(String collectionUri) {
        Map<String, Object> collectionDetails = new HashMap<String, Object>();

        Document collection = null;
        collection = FSXMLRequestHandler.instance().getNodeProperties(collectionUri, 0, false);

        if (collection == null) {
            return null;
        }

        collectionDetails.put("collection", collection);
        collectionDetails.put("collectionUri", collectionUri);

        Map<String, String> items = userConfigMemory.get(domainid + ":" + userid);

        for (String item : items.keySet()) {
            if (item.equals("collectiontitle")) {
                String collectionTitle = collection.selectSingleNode("//collection/properties/title") == null ? ""
                        : collection.selectSingleNode("//collection/properties/title").getText();
                collectionDetails.put(item, collectionTitle);
            } else if (item.equals("collectiondescription")) {
                String collectionDesc = collection.selectSingleNode("//collection/properties/description") == null
                        ? ""
                        : collection.selectSingleNode("//collection/properties/description").getText();
                collectionDetails.put(item, collectionDesc);
            } else if (item.equals("collectionstatus")) {
                String collectionStatus = collection
                        .selectSingleNode("//collection/properties/publicationstatus") == null ? ""
                                : collection.selectSingleNode("//collection/properties/publicationstatus")
                                        .getText();
                collectionDetails.put(item, collectionStatus);
            }
        }
        return collectionDetails;
    }

    //Collection details
    private Map<String, Object> getCollectionDetails(Document collection, String uri) {
        Map<String, Object> collectionDetails = new HashMap<String, Object>();

        String collectionUri = uri + "/" + collection.selectSingleNode("//collection/@id").getText() + "/";

        collectionDetails.put("collection", collection);
        collectionDetails.put("collectionUri", collectionUri);

        Map<String, String> items = userConfigMemory.get(domainid + ":" + userid);

        for (String item : items.keySet()) {
            if (item.equals("collectiontitle")) {
                String collectionTitle = collection.selectSingleNode("//collection/properties/title") == null ? ""
                        : collection.selectSingleNode("//collection/properties/title").getText();
                collectionDetails.put(item, collectionTitle);
            } else if (item.equals("collectiondescription")) {
                String collectionDesc = collection.selectSingleNode("//collection/properties/description") == null
                        ? ""
                        : collection.selectSingleNode("//collection/properties/description").getText();
                collectionDetails.put(item, collectionDesc);
            } else if (item.equals("collectionstatus")) {
                collection = collection == null
                        ? FSXMLRequestHandler.instance().getNodeProperties(collectionUri, 0, false)
                        : collection;
                String collectionStatus = collection
                        .selectSingleNode("//collection/properties/publicationstatus") == null ? ""
                                : collection.selectSingleNode("//collection/properties/publicationstatus")
                                        .getText();
                collectionDetails.put(item, collectionStatus);
            }
        }
        return collectionDetails;
    }

    // Delete the old collection in the index
    private void deleteTypes(String collectionUri) {
        logger.debug("deleting " + indexSaveType + " with collectionUri " + collectionUri);
        // get index types refering to collection
        List<String> refers = FSXMLRequestHandler.instance().getReferParents(collectionUri);

        // Delete all refers that are of type index type in the current index & same domain
        for (Iterator<String> iter = refers.iterator(); iter.hasNext();) {
            String refer = iter.next();

            if (refer.startsWith("/")) {
                refer = refer.substring(1);
            }
            String[] parts = refer.split("/");

            if (parts[1].equals(domainid) && parts[3].equals(userid) && parts[4].equals("index")
                    && parts[6].equals(indexSaveType)) {
                String cid = parts[7];
                //logger.debug("delete index type "+cid);
                logger.debug("deleting " + indexUri + "/" + indexSaveType + "/" + cid);
                FSXMLRequestHandler.instance().deleteNodeProperties(indexUri + "/" + indexSaveType + "/" + cid,
                        true);
            }
        }
    }

    //Loop over type
    private void loopTypes(String collectionUri, Map<String, Object> collectionDetails) {
        logger.debug("loop types");

        Document collection = (Document) collectionDetails.get("collection");

        List<Node> types = collection.selectNodes("//" + indexType);
        logger.debug("number of " + indexType + " = " + types.size());

        if (types.isEmpty()) {
            makeTypeFromCollection(collectionDetails);
        }

        //loop over type
        for (Iterator<Node> iter = types.iterator(); iter.hasNext();) {
            Element type = (Element) iter.next();
            makeType(type, collectionDetails);
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                logger.error("", e);
            }
        }
    }

    // Create an empty index
    private void createIndex() {
        FSXMLRequestHandler.instance().handlePUT(indexUri + "/properties", "<fsxml><properties><lastupdate>"
                + String.valueOf(new Date().getTime()) + "</lastupdate></properties></fsxml>");
    }

    // Get the number of collections for this uri
    private int getNumberOfCollections(String collectionUri) {
        Document collections = FSXMLRequestHandler.instance().getNodePropertiesByType(collectionUri, 0, 0, 1);
        Node resultsAvailable = collections.selectSingleNode("//properties/totalResultsAvailable");
        return Integer.parseInt(resultsAvailable.getText());
    }
}