com.xpn.xwiki.plugin.workspacesmanager.apps.DefaultWorkspaceApplicationManager.java Source code

Java tutorial

Introduction

Here is the source code for com.xpn.xwiki.plugin.workspacesmanager.apps.DefaultWorkspaceApplicationManager.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.plugin.workspacesmanager.apps;

import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Object;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.plugin.applicationmanager.ApplicationManagerPlugin;
import com.xpn.xwiki.plugin.applicationmanager.ApplicationManagerPluginApi;
import com.xpn.xwiki.plugin.applicationmanager.doc.XWikiApplication;
import com.xpn.xwiki.plugin.spacemanager.api.SpaceManagerException;
import com.xpn.xwiki.plugin.workspacesmanager.WorkspacesManagerException;
import com.xpn.xwiki.plugin.workspacesmanager.WorkspacesManagerExtension;

/**
 * The default manager for Workspaces Applications.
 * 
 * @version $Id$
 */
public class DefaultWorkspaceApplicationManager implements WorkspaceApplicationManager {

    /**
     * The dot, used as separator between wiki space and page names, in a wiki document full name.
     */
    public static final String XWIKI_SPACE_SEPARATOR = ".";

    /**
     * The separator used in a wiki space name to separate the name of the space from the name of the application.
     */
    public static final String XWIKI_WORKSPACE_APPSEPARATOR = "_";

    /**
     * A Single quote.
     */
    private static final String SINGLE_QUOTE = "'";

    /**
     * The wiki name of the document holding the XClass definition for XWiki Workspaces applications.
     */
    private static final String WORKSPACE_APPLICATION_CLASS = "XWiki.XWSApplicationClass";

    /**
     * Log object to log messages in this class.
     */
    private static final Log LOG = LogFactory.getLog(DefaultWorkspaceApplicationManager.class);

    /**
     * Set of all existing XWiki Workspaces applications.
     */
    private Set<String> allWorkspacesApps;

    /**
     * The API of the XWiki application manager plugin.
     */
    private ApplicationManagerPluginApi xwikiApplicationManagerApi;

    /**
     * Lazily instanciate the application manager api.
     * 
     * @return the {@link ApplicationManagerPluginApi} instance
     * @param context the {@link com.xpn.xwiki.XWikiContext} at the moment this method is called.
     */
    private ApplicationManagerPluginApi getXWikiApplicationManagerApi(XWikiContext context) {
        if (xwikiApplicationManagerApi == null) {
            xwikiApplicationManagerApi = (ApplicationManagerPluginApi) context.getWiki()
                    .getPluginApi(ApplicationManagerPlugin.PLUGIN_NAME, context);
        }
        return xwikiApplicationManagerApi;
    }

    /**
     * {@inheritDoc}
     */
    public Map<String, String> getApplicationsForSpace(String spaceName, XWikiContext context)
            throws WorkspacesManagerException {
        String hql = "select distinct doc.space from XWikiDocument as doc, XWikiDocument as sp"
                + ", BaseObject as xws, BaseObject as prefs, StringProperty as parent" + " where sp.space='"
                + spaceName + "' and sp.name='WebPreferences' and xws.name=sp.fullName" + " and xws.className='"
                + WorkspacesManagerExtension.WORKSPACE_SPACE_CLASS_NAME + SINGLE_QUOTE
                + " and prefs.className='XWiki.XWikiPreferences' and prefs.name=doc.fullName"
                + " and parent.id.id=prefs.id and parent.id.name='parent'" + " and parent.value='" + spaceName
                + SINGLE_QUOTE;
        try {
            List<String> applicationWebs = context.getWiki().getStore().search(hql, 0, 0, context);
            Map<String, String> result = new HashMap<String, String>();
            for (String appWeb : applicationWebs) {
                // Retrieve the application name based on it URL
                // Convention for an app web : Space_Spacename_Appname
                String appName = appWeb
                        .substring(appWeb.lastIndexOf(WorkspacesManagerExtension.XWIKI_WORKSPACE_APPSEPARATOR) + 1);
                result.put(appName, appWeb);
            }
            return result;
        } catch (XWikiException e) {
            throw new WorkspacesManagerException(e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public String getApplicationURL(String spaceName, String appName, String docName, String queryString,
            XWikiContext context) throws WorkspacesManagerException {
        try {
            String appWeb = getApplicationsForSpace(spaceName, context).get(appName);
            if (appWeb == null || appWeb.equals("")) {
                throw new WorkspacesManagerException(WorkspacesManagerException.MODULE_PLUGIN_XWS,
                        WorkspacesManagerException.ERROR_XWSMGR_APPNOTFOUNDFORSPACE,
                        "Application could not be found for space");
            }
            return context.getWiki().getURL(appWeb + WorkspacesManagerExtension.XWIKI_SPACE_SEPARATOR + docName,
                    "view", queryString, context);
        } catch (SpaceManagerException e) {
            throw new WorkspacesManagerException(e);
        } catch (XWikiException e) {
            throw new WorkspacesManagerException(e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public Set<String> getAvailableApplicationsNames(String spaceName, XWikiContext context)
            throws WorkspacesManagerException {
        Set<String> availableApps = getAllWorkspacesApps(context);
        Set<String> installedApps = getApplicationsForSpace(spaceName, context).keySet();
        availableApps.removeAll(installedApps);
        return availableApps;
    }

    /**
     * @param context the XWiki context at the moment this method is called.
     * @return a set of all available applications names that can be installed in a workspace.
     */
    private Set<String> getAllWorkspacesApps(XWikiContext context) {
        if (allWorkspacesApps == null) {
            allWorkspacesApps = new HashSet<String>();
            try {
                List<XWikiApplication> allApps = getXWikiApplicationManagerApi(context)
                        .getApplicationDocumentList();
                for (XWikiApplication app : allApps) {
                    if (app.getObject(WORKSPACE_APPLICATION_CLASS) != null) {
                        allWorkspacesApps.add(app.getAppName());
                    }
                }
            } catch (XWikiException e) {
                allWorkspacesApps = null;
                return Collections.emptySet();
            }
        }
        return allWorkspacesApps;
    }

    /**
     * {@inheritDoc}
     */
    public void removeApplicationFromSpace(String appName, String spaceName, boolean withData, XWikiContext context)
            throws WorkspacesManagerException {
        try {
            XWikiApplication app = getXWikiApplicationManagerApi(context).getApplicationDocument(appName);

            if (app == null) {
                throw new WorkspacesManagerException(WorkspacesManagerException.MODULE_PLUGIN_XWS,
                        WorkspacesManagerException.ERROR_XWSMGR_APPNOTFOUND_ON_INSTALL,
                        "Could not find application descriptor when trying to remove application [" + appName + "]"
                                + "from space [" + spaceName + "]");
            }
            String appSpace = spaceName + XWIKI_WORKSPACE_APPSEPARATOR + app.getAppName();

            if (!withData) {
                // not implemented yet.
                throw new WorkspacesManagerException();
            } else {
                ApplicationManagerExtension ext = getApplicationManagerExtension(app, context);
                // execute, if needed pre uninstall operations
                if (ext != null) {
                    ext.preUninstall(appSpace, context);
                }
                // remove all documents that belong to the wiki space in which lives the application
                for (XWikiDocument doc : context.getWiki().getStore()
                        .searchDocuments("where doc.space = '" + appSpace + SINGLE_QUOTE, context)) {
                    context.getWiki().deleteAllDocuments(doc, false, context);
                }
                // execute, if needed post uninstall operations
                if (ext != null) {
                    ext.postUninstall(appSpace, context);
                }
            }
        } catch (XWikiException e) {
            throw new WorkspacesManagerException(e);
        }
    }

    /**
     * @param app the application to retrieve the extension for
     * @param context the XWiki context at the moment this method is called.
     * @return the {@link ApplicationManagerExtension} corresponding to the passe application
     */
    private ApplicationManagerExtension getApplicationManagerExtension(XWikiApplication app, XWikiContext context) {
        Object xwsApp = app.getObject(WORKSPACE_APPLICATION_CLASS);
        if (xwsApp != null) {
            String cName = (String) xwsApp.get("application_manager_extension");
            if (cName != null && !cName.equals("")) {
                try {
                    java.lang.Object c = Class.forName(cName).newInstance();
                    if (c instanceof ApplicationManagerExtension) {
                        return (ApplicationManagerExtension) c;
                    } else {
                        String msg = "could not load application manager extension  "
                                + " for application [{0}], as provided class [{1}] does not"
                                + " implements ApplicationManagerExtension interface.";
                        msg = MessageFormat.format(msg,
                                new java.lang.Object[] { app.getName(), c.getClass().getName() });
                        LOG.error(msg);
                    }
                } catch (Exception e) {
                    LOG.error(e);
                }
            }
        }
        return null;
    }

    /**
     * Install an application in the given space, by copying or linking documents. Read the list of documents to include
     * (link) and copy from the {@link ApplicationManagerPlugin} and save their content locally in a wiki space (web)
     * composed of the space wiki name and the application name. Also make the application web inherits its rights from
     * the space root space (web).
     * 
     * @param appName the name of the application to install
     * @param spaceName the wiki name of the space to install the application in
     * @param context the XWiki context at the moment this method is called.
     * @throws WorkspacesManagerException a wrapped error that can occur while searching documents, or manipulating them
     *             (copying, saving) ; or an exception raised by extension pre-install or post-install operations
     */
    public void installApplicationInSpace(String appName, String spaceName, XWikiContext context)
            throws WorkspacesManagerException {
        // TODO Note that this method makes a deviant usage of the application
        // manager plugin and XWiki application objects.
        // It uses the application field docsToInclude and documents
        // to make a local installation (as opposed as cross-wiki global
        // installation, which the application manager is initially designed
        // for).
        // In the future, the application manager should be able to
        // handle local installation/local copy parameters, and the
        // SpaceManagerPlugin implements a method to install a space
        // from an application or application list.

        // get the application manager api

        try {
            // Retrieve the application descriptor
            XWikiApplication app = getXWikiApplicationManagerApi(context).getApplicationDocument(appName);

            if (app == null) {
                throw new WorkspacesManagerException(WorkspacesManagerException.MODULE_PLUGIN_XWS,
                        WorkspacesManagerException.ERROR_XWSMGR_APPNOTFOUND_ON_INSTALL,
                        "Could not find application descriptor when trying to install application [" + appName + "]"
                                + "in space [" + spaceName + "]");
            }
            ApplicationManagerExtension ext = getApplicationManagerExtension(app, context);

            String appSpace = spaceName + XWIKI_WORKSPACE_APPSEPARATOR + app.getAppName();

            // execute, if needed pre install operations
            if (ext != null) {
                ext.preInstall(appSpace, context);
            }

            // Retrieve the application document list
            Set<String> appDocs = app.getDocumentsNames(false, false);

            // Retrieve the application documents to include
            Set<String> docsToInclude = app.getDocsNameToInclude(true);

            for (String docFullName : appDocs) {
                // If the doc is not in the include list,
                // We copy it to the target space
                if (!docsToInclude.contains(docFullName)) {
                    String docName = docFullName.substring(docFullName.indexOf('.') + 1);
                    String targetDocName = appSpace + XWIKI_SPACE_SEPARATOR + docName;
                    // copy the document, with metadata (dates, author, etc.) reset
                    context.getWiki().copyDocument(docFullName, targetDocName, null, null, null, false, false, true,
                            context);
                }
            }

            for (String docFullName : docsToInclude) {

                String docName = docFullName.substring(docFullName.indexOf('.') + 1);

                // Compute the target doc name based on application name, space
                // name and document
                // name
                // EX: Space_Wiki.WebHome for "Space" space name, "Wiki" appname
                // and "WebHome" doc
                String targetDocName = appSpace + XWIKI_SPACE_SEPARATOR + docName;
                XWikiDocument targetDoc = context.getWiki().getDocument(targetDocName, context);

                // Link the content with the application code
                targetDoc.setContent(
                        MessageFormat.format("#includeInContext(\"{0}\")", new java.lang.Object[] { docFullName }));

                // Save the document
                context.getWiki().saveDocument(targetDoc, context);
            }

            if (appDocs.size() > 0) {
                // if we've installed anything,
                // make the installed app inherit its right from the Workspace
                // root web
                XWikiDocument appPreferences = context.getWiki()
                        .getDocument(appSpace + XWIKI_SPACE_SEPARATOR + "WebPreferences", context);
                BaseObject pObj = appPreferences.getObject("XWiki.XWikiPreferences", true, context);
                pObj.setStringValue("parent", spaceName);
                context.getWiki().saveDocument(appPreferences, context);
            }

            // execute, if needed post install operations
            if (ext != null) {
                ext.postInstall(appSpace, context);
            }

        } catch (XWikiException e) {
            throw new WorkspacesManagerException(e);
        }
    }
}