org.bungeni.ext.integration.bungeniportal.BungeniServiceAccess.java Source code

Java tutorial

Introduction

Here is the source code for org.bungeni.ext.integration.bungeniportal.BungeniServiceAccess.java

Source

/*
 * Copyright (C) 2012 UN/DESA Africa i-Parliaments Action Plan
 *
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.bungeni.ext.integration.bungeniportal;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.bungeni.editor.config.BungeniEditorPropertiesHelper;
import org.bungeni.ext.integration.bungeniportal.BungeniAppConnector.WebResponse;
import org.bungeni.ext.integration.bungeniportal.docimpl.BungeniAtt;
import org.bungeni.ext.integration.bungeniportal.docimpl.BungeniAttachment;
import org.bungeni.ext.integration.bungeniportal.docimpl.BungeniDoc;
import org.bungeni.ext.integration.bungeniportal.docimpl.BungeniDocument;
import org.bungeni.ext.integration.bungeniportal.docimpl.BungeniListDocuments;
import org.bungeni.ext.integration.bungeniportal.docimpl.BungeniListDocuments.BungeniListDocument;
import org.bungeni.ext.integration.bungeniportal.docimpl.Transition;
import org.bungeni.odfdom.document.BungeniOdfDocumentHelper;
import org.bungeni.odfdom.document.properties.BungeniOdfPropertiesHelper;
import org.bungeni.odfdom.section.BungeniOdfSectionHelper;
import org.jdom.JDOMException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.dom.element.text.TextSectionElement;
import org.w3c.dom.NodeList;

/**
 * This is the class that implements all interaction with Bungeni and abstracts
 * that interaction to the rest of the Bungeni Editor.
 *
 * @author Ashok Hariharan
 */
public class BungeniServiceAccess {

    private static BungeniServiceAccess instance = null;
    private static org.apache.log4j.Logger log = org.apache.log4j.Logger
            .getLogger(BungeniServiceAccess.class.getName());
    BungeniAppConnector appConnector = null;
    DefaultHttpClient client = null;

    public static BungeniServiceAccess getInstance() {
        if (null == instance) {
            instance = new BungeniServiceAccess();
        }
        return instance;
    }

    public BungeniAppConnector getAppConnector() {
        return this.appConnector;
    }

    /**
     * Does the initial login when there is no oauth cache / refresh token
     * This does the initial Oauth negotiation and authentication code retrieval
     * @param loginInfo
     * @param user
     * @param password
     * @return
     * @throws UnsupportedEncodingException
     * @throws IOException
     * @throws JDOMException 
     */
    public DefaultHttpClient login(LoginInfo loginInfo, String user, String password)
            throws UnsupportedEncodingException, IOException, JDOMException {
        if (null == appConnector) {
            this.appConnector = new BungeniAppConnector(loginInfo, user, password);
            this.client = appConnector.oauthLogin();
            return this.client;
        }
        return null;
    }

    /**
     * Logs in via a OAuth Access token. This is called when the cached
     * access token has expired during 1st time login 
     * @param loginInfo
     * @return 
     */
    public DefaultHttpClient loginViaOauthToken(LoginInfo loginInfo) {
        if (null == appConnector) {
            this.appConnector = new BungeniAppConnector(loginInfo, null, null);
            try {
                this.client = appConnector.oauthAccessTokenLogin();
                return this.client;
            } catch (FileNotFoundException ex) {
                log.error("OAuth properties file not found", ex);
            } catch (IOException ex) {
                log.error("Erorr while reading oauth.properties file", ex);
            }
        }
        return null;
    }

    /**
     * If the access token is valid this is used to do a blind login.
     * @param loginInfo
     * @return 
     */
    public DefaultHttpClient loginBlind(LoginInfo loginInfo) {
        if (null == appConnector) {
            this.appConnector = new BungeniAppConnector(loginInfo, null, null);
            this.client = appConnector.oauthBlindLogin();
            return this.client;
        }
        return null;
    }

    private static Map<String, String> getQueryMap(String query) {
        String[] params = query.split("&");
        Map<String, String> map = new HashMap<String, String>();
        for (String param : params) {
            String name = param.split("=")[0];
            String value = param.split("=")[1];
            map.put(name, value);
        }
        return map;
    }

    private String getTargetTransitionId(String transitionURL) throws MalformedURLException {
        URL url = new URL(transitionURL);
        String sUrlQuery = url.getQuery();
        Map<String, String> urlMap = getQueryMap(sUrlQuery);
        String sTransition = urlMap.get("transition_id");
        String[] arrTrans = sTransition.split("-");
        // the second element in the array has the transition id 
        String targetTransitionId = arrTrans[1];
        return targetTransitionId;
    }

    public String getTransitionTime(Date dTime) {
        Calendar c = Calendar.getInstance();
        c.setTime(dTime);
        StringBuilder sTime = new StringBuilder();
        sTime.append(c.get(Calendar.HOUR));
        sTime.append(":");
        sTime.append(c.get(Calendar.MINUTE));
        return sTime.toString();
    }

    public String getTransitionDate(Date dtDate) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(dtDate);
    }

    /**
    public List<BasicNameValuePair> attachmentUploadFormFields(String sAttURL, List<BasicNameValuePair> inputFormSubmit) {
       List<BasicNameValuePair> nvPair = new ArrayList<BasicNameValuePair>(0);
       //nvPair.add(new BasicNameValuePair("container_contents_versions.commit_message", ))
           
       return null;   
    }
    ***/

    public List<BasicNameValuePair> attachmentWorkflowTransitPostQuery(Transition transObj, String sDate,
            String sTime, List<BasicNameValuePair> inputFormFields) throws MalformedURLException {

        List<BasicNameValuePair> nvPair = new ArrayList<BasicNameValuePair>(0);

        nvPair.add(new BasicNameValuePair("next_url", "./workflow-redirect"));

        nvPair.add(new BasicNameValuePair("form.date_active", sDate));

        nvPair.add(new BasicNameValuePair("form__date_active__time", sTime));

        for (BasicNameValuePair inputFormField : inputFormFields) {
            // !+WARNING+WARNING - assumption is that 2 transitions dont have the same
            // name !
            if (inputFormField.getValue().equalsIgnoreCase(transObj.title)) {
                nvPair.add(inputFormField);
                break;
            }
        }
        return nvPair;
    }

    public String toHex(String arg) throws UnsupportedEncodingException {
        return String.format("%x", new BigInteger(arg.getBytes("UTF-8")));
    }

    public String transitionNameAsciiAble(String name) throws UnsupportedEncodingException {
        // from zope.formlib.form.Action :
        /**
         * class Action(object):
            
        interface.implements(interfaces.IAction)
        _identifier = re.compile('[A-Za-z][a-zA-Z0-9_]*$')
         */
        String pattern = "^[A-Za-z][a-zA-Z0-9_]*$";
        if (name.matches(pattern)) {
            return name.toLowerCase();
        } else {
            return toHex(name);
        }
    }

    /**
     * This api returns the form information for submitting a transition.
     * We make 2 calls 2 this form
     * this is the first one it determines the fields on the form and the submit actions
     * @param docURL
     * @return 
     */
    public List<BasicNameValuePair> getWfTransitionInputTypeSubmitInfo(String docURL) {
        List<BasicNameValuePair> nvp = new ArrayList<BasicNameValuePair>();
        WebResponse wr = appConnector.getUrl(makeWFurl(docURL), false);
        if (wr.getStatusCode() == 200) {
            Document wfDoc = Jsoup.parse(wr.getResponseBody());
            nvp = getActionsViewButtonInfo(wfDoc);
        }
        return nvp;
    }

    public List<BasicNameValuePair> attachmentVersionSubmitPostQuery(List<BasicNameValuePair> pairs,
            String sComment) {

        List<BasicNameValuePair> nvPair = new ArrayList<BasicNameValuePair>(0);
        nvPair.add(new BasicNameValuePair("container_contents_versions.commit_message", sComment));

        for (BasicNameValuePair inputFormField : pairs) {
            if (inputFormField.getName().equalsIgnoreCase("container_contents_versions.actions.new_version")) {
                nvPair.add(inputFormField);
                break;
            }
        }

        return nvPair;
    }

    private List<BasicNameValuePair> getActionsViewButtonInfo(Document doc) {
        List<BasicNameValuePair> nvp = new ArrayList<BasicNameValuePair>(0);
        Elements inputList = doc.select("div#actionsView input");
        for (int i = 0; i < inputList.size(); i++) {
            Element inputItem = inputList.get(i);
            nvp.add(new BasicNameValuePair(inputItem.attr("name"), inputItem.attr("value")));
        }
        return nvp;
    }

    private List<BasicNameValuePair> getFormFieldSelectDefaultValues(Document doc, List<String> fieldNames) {
        List<BasicNameValuePair> nvp = new ArrayList<BasicNameValuePair>(0);
        for (String fieldName : fieldNames) {
            Elements inputItems = doc.select("[name=" + fieldName + "]");
            for (int i = 0; i < inputItems.size(); i++) {
                Element inputItem = inputItems.get(i);
                Elements selItems = inputItem.select("[selected=selected]");
                for (int j = 0; j < selItems.size(); j++) {
                    Element selItem = selItems.get(j);
                    nvp.add(new BasicNameValuePair(fieldName, selItem.attr("value")));
                }
            }
        }
        return nvp;
    }

    /**
     * THis API gets all the submit buttons for Attachment submission
     * Also gets the default values for the selection dropdowns
     * @param docURL
     * @return 
     */
    public HashMap<String, ContentBody> getAttachmentEditSubmitInfo(String docURL) {
        HashMap<String, ContentBody> formFields = new HashMap<String, ContentBody>();
        // List<BasicNameValuePair> nvp = new ArrayList<BasicNameValuePair>();
        WebResponse wr = appConnector.getUrl(this.makeEditUrl(docURL), false);

        if (wr.getStatusCode() == 200) {
            Document wfDoc = Jsoup.parse(wr.getResponseBody());
            // get the action buttons
            List<BasicNameValuePair> nvp = this.getActionsViewButtonInfo(wfDoc);
            // filter the action buttons, we want only the save acttion
            for (BasicNameValuePair pair : nvp) {
                try {
                    if (pair.getName().equals("form.actions.save")) {
                        formFields.put(pair.getName(), new StringBody(pair.getValue()));
                    }
                } catch (UnsupportedEncodingException ex) {
                    log.error("Encoding error while adding field " + pair.getName(), ex);
                }
            }
            // get the other defaulted fields
            List<String> defaultFields = new ArrayList<String>() {
                {
                    add("form.language");
                    add("form.type");
                }
            };
            // get the default values for fields
            for (BasicNameValuePair defField : this.getFormFieldSelectDefaultValues(wfDoc, defaultFields)) {
                try {
                    formFields.put(defField.getName(), new StringBody(defField.getValue()));
                } catch (UnsupportedEncodingException ex) {
                    log.error("Error encoding field value " + defField.getName(), ex);
                }
            }

        }
        return formFields;
    }

    public HashMap<String, ContentBody> attachmentEditSubmitPostQuery(HashMap<String, ContentBody> formFields,
            String title, String description, String fFileName) {
        try {
            formFields.put("form.title", new StringBody(title));
            formFields.put("form.data.up_action", new StringBody("update"));
            formFields.put("form_data_file", new FileBody(new File(new URI(fFileName)), getMimeType(fFileName)));
            formFields.put("form.description", new StringBody(description));
            formFields.put("form.language-empty-marker", new StringBody("1"));
            formFields.put("form.type-empty-marker", new StringBody("1"));
            return formFields;
        } catch (URISyntaxException ex) {
            log.error("Error getting URI to file ", ex);
            return formFields;
        } catch (UnsupportedEncodingException ex) {
            log.error("Encoding exception for field ", ex);
            return formFields;
        }
    }

    public List<BasicNameValuePair> getAttachmentVersionSubmitInfo(String docURL) {

        List<BasicNameValuePair> nvp = new ArrayList<BasicNameValuePair>();
        WebResponse wr = appConnector.getUrl(this.makeVersionUrl(docURL), false);

        if (wr.getStatusCode() == 200) {
            Document wfDoc = Jsoup.parse(wr.getResponseBody());
            nvp = getActionsViewButtonInfo(wfDoc);
        }
        return nvp;
    }

    public String makeWFurl(String docURL) {
        return docURL + "/workflow";
    }

    public String makeVersionUrl(String docURL) {
        return docURL + "/version-log";
    }

    public String makeEditUrl(String docURL) {
        return docURL + "/edit";
    }

    public WebResponse doVersion(String docURL, List<BasicNameValuePair> nvp) throws UnsupportedEncodingException {
        String versionURL = makeVersionUrl(docURL);
        WebResponse wr = appConnector.multipartPostUrl(versionURL, false, nvp);
        return wr;
    }

    public WebResponse doTransition(String docURL, List<BasicNameValuePair> nvp)
            throws UnsupportedEncodingException {
        String wfUrl = makeWFurl(docURL);
        WebResponse wr = appConnector.multipartPostUrl(wfUrl, false, nvp);
        return wr;
    }

    public WebResponse doEdit(String docURL, HashMap<String, ContentBody> nvp) throws UnsupportedEncodingException {
        String editURL = makeEditUrl(docURL);
        WebResponse wr = appConnector.multipartPostUrl(editURL, false, nvp);
        return wr;
    }

    public Map<String, String> getAuthorizationHeaders() {
        Map<String, String> reqHeaders = new HashMap<String, String>() {
            {
                put("Authorization", "Bearer " + OAuthProperties.getInstance().getAccessToken());
            }
        };
        return reqHeaders;
    }

    public List<BungeniListDocument> availableDocumentsForEditing(String sSearchBungeniURL) {
        List<BungeniListDocument> bungeniDocs = new ArrayList<BungeniListDocument>(0);
        WebResponse wr = appConnector.getUrl(sSearchBungeniURL, true, getAuthorizationHeaders());
        if (wr != null) {
            if (wr.getStatusCode() == 200) {
                String sResponseBody = wr.getResponseBody();
                BungeniListDocuments bld = new BungeniListDocuments(sSearchBungeniURL, sResponseBody);
                bungeniDocs = bld.getListDocuments();
            }
        }
        return bungeniDocs;
    }

    /**
     * Service api called from BungeniAttLoadingPanel
     *
     * @param fodf
     * @param aDocument
     * @return
     * @throws Exception
     */
    public File checkOdfDocument(File fodf, BungeniDoc aDocument) throws Exception {
        OdfDocument odf = OdfDocument.loadDocument(fodf);
        BungeniOdfDocumentHelper odfhelper = new BungeniOdfDocumentHelper(odf);
        BungeniOdfPropertiesHelper propshelper = odfhelper.getPropertiesHelper();
        //check if the document has been edited in bungeni editor .. look for some properties
        HashMap<String, String> docPropsMap = propshelper.getUserDefinedPropertyValues();
        //check for root section
        boolean rootSectionExists = false;
        BungeniOdfSectionHelper sechelper = odfhelper.getSectionHelper();
        NodeList sections = sechelper.getDocumentSections();
        if (sections.getLength() > 0) {
            TextSectionElement sectionElement = (TextSectionElement) sections.item(0);
            //check for body section Type
            String sBody = sechelper.getSectionMetadataValue(sectionElement, "BungeniSectionType");
            if (sBody.equals("body")) {
                rootSectionExists = true;
            }
        }

        // if (this.hasDocumentBeeenEditedByTheEditor(docPropsMap, rootSectionExists)) {
        // this is a bungeni document ... load for editing
        // TO DO 
        // } else {
        //first prepare the document
        BungeniAtt att = aDocument.getSelectedAttachment();
        propshelper.setUserDefinedPropertyValue("BungeniDocType",
                BungeniEditorPropertiesHelper.getCurrentDocType());
        propshelper.setUserDefinedPropertyValue("DocSource", "BungeniPortal");
        propshelper.setUserDefinedPropertyValue("DocEditor", "BungeniEditor");
        propshelper.setUserDefinedPropertyValue("DocInit", "False");
        propshelper.setUserDefinedPropertyValue("PortalSourceDoc", aDocument.getStatus().getValue());
        propshelper.setUserDefinedPropertyValue("PortalSourceTitle", aDocument.getTitle());
        propshelper.setUserDefinedPropertyValue("PortalSourceURL", aDocument.getDocumentURL());
        propshelper.setUserDefinedPropertyValue("PortalAttSource", att.getDocumentURL());
        propshelper.setUserDefinedPropertyValue("PortalAttFileName", att.getName());
        propshelper.setUserDefinedPropertyValue("PortalAttTitle", att.getTitle());
        propshelper.setUserDefinedPropertyValue("PortalAttType", att.getType());
        propshelper.setUserDefinedPropertyValue("PortalAttMimeType", att.getMimetype());
        propshelper.setUserDefinedPropertyValue("PortalAttLang", att.getLanguage());
        propshelper.setUserDefinedPropertyValue("PortalAttStatus", att.getStatus().getValue());
        propshelper.setUserDefinedPropertyValue("PortalAttStatusDate", att.getStatus_date());
        propshelper.setUserDefinedPropertyValue("PortalAttDownURL", att.getDocumentURL());
        propshelper.setUserDefinedPropertyValue("PortalAttDesc", att.getDescription());
        // !+FIX_THIS
        //propshelper.setUserDefinedPropertyValue("PortalAttTransCount", Integer.toString(att.transitions.size()));

        int i = 0;
        /* !+FIX_THIS
        for (Transition transition : att.transitions) {
            i++;
            //Not more than 99 transitions !!!
            String snum = String.format("%02d", i);
            propshelper.setUserDefinedPropertyValue("PortalAttTransName" + snum, transition.title);
            propshelper.setUserDefinedPropertyValue("PortalAttTransURL" + snum, transition.url);
        }
        */
        odfhelper.saveDocument();
        // create the root section after opening and set initial metadata properties
        //}
        return fodf;
    }

    public boolean hasDocumentBeeenEditedByTheEditor(HashMap<String, String> docPropsMap,
            boolean rootSectionExists) {
        if (docPropsMap.containsKey("BungeniDocType") && docPropsMap.containsKey("DocSource")
                && docPropsMap.containsKey("DocEditor") && rootSectionExists) {
            if (docPropsMap.get("DocSource").equals("BungeniPortal")
                    && docPropsMap.get("DocEditor").equals("BungeniEditor")) {
                return true;
            }
        }
        return false;
    }

    public BungeniAttachment getAttachmentFromURL(String sURL) {
        WebResponse wr = appConnector.getUrl(sURL, false);
        if (wr.getStatusCode() == 200) {
            String responseBody = wr.getResponseBody();
            if (null != responseBody) {
                Document attDoc = Jsoup.parse(responseBody);
                BungeniAttachment att = new BungeniAttachment();
                att.parseAttachment(attDoc);
                return att;
            }
        }
        return null;
    }

    public List<Transition> getUpdatedTransitionsForAttachment(String sURL) {
        List<Transition> trans = new ArrayList<Transition>();
        BungeniAttachment att = this.getAttachmentFromURL(sURL);
        if (att != null) {
            return att.transitions;
        }
        return trans;
    }

    private String getItemAttributeValue(Document doc, String itemPath, String attributeReturn) {
        Elements item = doc.select(itemPath);
        return item.get(0).attr(attributeReturn);
    }

    public HashMap<String, ContentBody> getAuthorizeFormFieldValues(String sBody)
            throws UnsupportedEncodingException {
        HashMap<String, ContentBody> nvp = new HashMap<String, ContentBody>();
        Document doc = Jsoup.parse(sBody);
        if (!doc.select("input[name=client_id]").isEmpty()) {
            nvp.put("client_id", new StringBody(getItemAttributeValue(doc, "input[name=client_id]", "value")));
            nvp.put("state", new StringBody(getItemAttributeValue(doc, "input[name=state]", "value")));
            nvp.put("time", new StringBody(getItemAttributeValue(doc, "input[name=time]", "value")));
            nvp.put("nonce", new StringBody(getItemAttributeValue(doc, "input[name=nonce]", "value")));
            nvp.put("form.actions.authorize",
                    new StringBody(getItemAttributeValue(doc, "input[name=form.actions.authorize]", "value")));
        }
        return nvp;

    }

    public boolean createNewVersion(String docURL, String comment) {
        // version 

        //do soemthing
        return true;
    }

    public boolean uploadDocument(String toURL, File fFileToUpload) {
        // connect and upload

        // do something
        return true;
    }

    private String getMimeType(String fFileName) {
        if (fFileName.endsWith(".odt")) {
            return "application/vnd.oasis.opendocument.text";
        }
        if (fFileName.endsWith(".xml")) {
            return "text/xml";
        }
        return "application/octet-stream";
    }
}