Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)

99015: ACE-3703 - Refactor Repository Admin Console framework to allow the basic framework to work in Community version
    - Refactor of admin console core (non JMX) into Community project
    - Enterprise extensions extend core
    - Moved Interpreter consoles into Community Admin Console
    - Moved Node Browser into Community Admin Console


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@99076 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2015-03-09 21:20:38 +00:00
parent 58d58b2479
commit 48974b90cf
71 changed files with 1829 additions and 7 deletions

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.admin;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.alfresco.repo.admin.BaseInterpreter;
import org.alfresco.repo.processor.BaseProcessorExtension;
/**
* Console Interpeter script extension - dynamically binds to the configured BaseInterpreter instance.
* This avoids the need for a specific bean class per script interpreter.
*
* @see org.alfresco.repo.admin.BaseInterpreter
* See script beans configured in 'web-scripts-application-context.xml'.
*
* @author Kevin Roast
* @since 5.1
*/
public class DynamicInterpreterExtension extends BaseProcessorExtension
{
private BaseInterpreter interpreter;
private long duration;
private String result = "";
private String command = "";
/**
* Set the BaseInterpreter to use when executing commands and retrieving the command result.
*
* @param interpreter For example, repoAdminInterpreter
*/
public void setInterpreter(BaseInterpreter interpreter)
{
this.interpreter = interpreter;
}
private BaseInterpreter getInterpreter()
{
return this.interpreter;
}
/**
* Script execute command gateway.
*
* @param command string to execute
*/
public void executeCmd(String command)
{
this.command = command;
this.interpretCommand(command);
}
/**
* @return the command duration
*/
public long getDuration()
{
return this.duration;
}
/**
* @return the command result
*/
public String getResult()
{
return this.result;
}
/**
* @return the command last executed
*/
public String getCommand()
{
return this.command;
}
/**
* Interpret console command using the configured Interpreter
*
* @param command command
*/
private void interpretCommand(String command)
{
try
{
long startms = System.currentTimeMillis();
this.result = getInterpreter().interpretCommand(command);
this.duration = System.currentTimeMillis() - startms;
}
catch (Throwable e)
{
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
this.result = stackTrace.toString();
}
}
}

View File

@@ -0,0 +1,318 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco 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 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.web.scripts.admin;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.slingshot.web.scripts.NodeBrowserScript;
import org.alfresco.util.GUID;
import org.springframework.extensions.surf.util.URLEncoder;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
/**
* Admin Console NodeBrowser WebScript POST controller.
* <p>
* Implements a low-level node browser client for the Admin Console tool. Extends
* the slingshot NodeBrowserScript WebScript to share the useful value wrapper classes.
*
* @author Kevin Roast
* @since 5.1
*/
public class NodeBrowserPost extends NodeBrowserScript implements Serializable
{
private static final long serialVersionUID = 8464392337270665212L;
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
Map<String, Object> result = new HashMap<>(16);
// gather inputs
Map<String, String> returnParams = new HashMap<>(16);
String store = req.getParameter("nodebrowser-store");
String searcher = req.getParameter("nodebrowser-search");
String query = req.getParameter("nodebrowser-query");
String maxResults = req.getParameter("nodebrowser-query-maxresults");
String skipCount = req.getParameter("nodebrowser-query-skipcount");
String error = null;
StoreRef storeRef = new StoreRef(store);
// always a list of assoc refs from some result
List<ChildAssociationRef> assocRefs = Collections.<ChildAssociationRef>emptyList();
NodeRef currentNode = null;
// what action should be processed?
long timeStart = System.currentTimeMillis();
String actionValue = req.getParameter("nodebrowser-action-value");
String action = req.getParameter("nodebrowser-action");
try
{
switch (action)
{
// on Execute btn press and query present, perform search
case "search":
{
if (query != null && query.trim().length() != 0)
{
switch (searcher)
{
case "noderef":
{
// ensure node exists - or throw error
NodeRef nodeRef = new NodeRef(query);
boolean exists = getNodeService().exists(nodeRef);
if (!exists)
{
throw new AlfrescoRuntimeException("Node " + nodeRef + " does not exist.");
}
currentNode = nodeRef;
// this is not really a search for results, it is a direct node reference
// so gather the child assocs as usual and update the action value for the UI location
assocRefs = getNodeService().getChildAssocs(currentNode);
actionValue = query;
action = "parent";
break;
}
case "selectnodes":
{
List<NodeRef> nodes = getSearchService().selectNodes(
getNodeService().getRootNode(storeRef), query, null, getNamespaceService(), false);
assocRefs = new ArrayList<>(nodes.size());
for (NodeRef node: nodes)
{
assocRefs.add(getNodeService().getPrimaryParent(node));
}
break;
}
default:
{
// perform search
SearchParameters params = new SearchParameters();
params.setQuery(query);
params.addStore(storeRef);
params.setLanguage(searcher);
if (maxResults != null && maxResults.length() != 0)
{
params.setMaxItems(Integer.parseInt(maxResults));
params.setLimit(Integer.parseInt(maxResults));
}
if (skipCount != null && skipCount.length() != 0)
{
params.setSkipCount(Integer.parseInt(skipCount));
}
ResultSet rs = getSearchService().query(params);
assocRefs = rs.getChildAssocRefs();
break;
}
}
}
break;
}
case "root":
{
// iterate the properties and children of a store root node
currentNode = getNodeService().getRootNode(storeRef);
assocRefs = getNodeService().getChildAssocs(currentNode);
break;
}
case "parent":
case "children":
{
currentNode = new NodeRef(actionValue);
assocRefs = getNodeService().getChildAssocs(currentNode);
break;
}
}
// get the required information from the assocRefs list and wrap objects
List<ChildAssocRefWrapper> wrappers = new ArrayList<>(assocRefs.size());
for (ChildAssociationRef ref : assocRefs)
{
wrappers.add(new ChildAssocRefWrapper(ref));
}
result.put("children", wrappers);
}
catch (Throwable e)
{
// empty child list on error - current node will still be null
result.put("children", new ArrayList<>(0));
error = e.getMessage();
}
// current node info if any
if (currentNode != null)
{
// node info
Map<String, Object> info = new HashMap<>(8);
info.put("nodeRef", currentNode.toString());
info.put("path", getNodeService().getPath(currentNode).toPrefixString(getNamespaceService()));
info.put("type", getNodeService().getType(currentNode).toPrefixString(getNamespaceService()));
ChildAssociationRef parent = getNodeService().getPrimaryParent(currentNode);
info.put("parent", parent.getParentRef() != null ? parent.getParentRef().toString() : "");
result.put("info", info);
// node properties
result.put("properties", getProperties(currentNode));
// parents
List<ChildAssociationRef> parents = getNodeService().getParentAssocs(currentNode);
List<ChildAssociation> assocs = new ArrayList<ChildAssociation>(parents.size());
for (ChildAssociationRef ref : parents)
{
assocs.add(new ChildAssociation(ref));
}
result.put("parents", assocs);
// aspects
List<Aspect> aspects = getAspects(currentNode);
result.put("aspects", aspects);
// target assocs
List<PeerAssociation> targetAssocs = getAssocs(currentNode);
result.put("assocs", targetAssocs);
// source assocs
List<PeerAssociation> sourceAssocs = getSourceAssocs(currentNode);
result.put("sourceAssocs", sourceAssocs);
// permissions
Map<String, Object> permissionInfo = new HashMap<String, Object>();
permissionInfo.put("entries", getPermissions(currentNode));
permissionInfo.put("owner", getOwnableService().getOwner(currentNode));
permissionInfo.put("inherit", getInheritPermissions(currentNode));
result.put("permissions", permissionInfo);
}
// store result in session for the resulting GET request webscript
final String resultId = GUID.generate();
HttpServletRequest request = ((WebScriptServletRequest)req).getHttpServletRequest();
HttpSession session = request.getSession();
session.putValue(resultId, result);
// return params
returnParams.put("resultId", resultId);
returnParams.put("action", action);
returnParams.put("actionValue", actionValue);
returnParams.put("query", query);
returnParams.put("store", store);
returnParams.put("searcher", searcher);
returnParams.put("maxResults", maxResults);
returnParams.put("skipCount", skipCount);
returnParams.put("in", Long.toString(System.currentTimeMillis()-timeStart));
returnParams.put("e", error);
// redirect as all admin console pages do (follow standard pattern)
// The logic to generate the navigation section and server meta-data is all tied into alfresco-common.lib.js
// which is great for writing JS based JMX surfaced pages, but not so great for Java backed WebScripts.
status.setCode(301);
status.setRedirect(true);
status.setLocation(buildUrl(req, returnParams, action));
return null;
}
private static String buildUrl(WebScriptRequest req, Map<String, String> params, String hash)
{
StringBuilder url = new StringBuilder(256);
url.append(req.getServicePath());
if (!params.isEmpty())
{
boolean first = true;
for (String key: params.keySet())
{
String val = params.get(key);
if (val != null && val.length() != 0)
{
url.append(first ? '?' : '&');
url.append(key);
url.append('=');
url.append(URLEncoder.encode(val));
first = false;
}
}
}
if (hash != null && hash.length() != 0)
{
url.append('#').append(hash);
}
return url.toString();
}
/**
* Wrapper to resolve Assoc Type and QName to short form with resolved prefix
*/
public class ChildAssocRefWrapper implements Serializable
{
private static final long serialVersionUID = 4321292337846270665L;
final private ChildAssociationRef ref;
private String qname = null;
private String typeqname = null;
public ChildAssocRefWrapper(ChildAssociationRef r)
{
ref = r;
}
public String getTypeQName()
{
return typeqname != null ? typeqname : (typeqname = ref.getTypeQName().toPrefixString(getNamespaceService()));
}
public String getQName()
{
return qname != null ? qname : (qname = ref.getQName().toPrefixString(getNamespaceService()));
}
public NodeRef getChildRef()
{
return ref.getChildRef();
}
public NodeRef getParentRef()
{
return ref.getParentRef();
}
public boolean isPrimary()
{
return ref.isPrimary();
}
}
}