Moved web script classes and definitions out of web-client project and into remote-api

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8956 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Roy Wetherall
2008-04-29 19:41:59 +00:00
parent 8d0db44bc6
commit d12effa6d6
201 changed files with 14060 additions and 11 deletions

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import java.util.HashMap;
import org.alfresco.web.scripts.TestWebScriptServer;
import org.springframework.mock.web.MockHttpServletResponse;
import junit.framework.TestCase;
/**
* Base unit test class for web scripts.
*
* @author Roy Wetherall
*/
public abstract class BaseWebScriptTest extends TestCase
{
/** Standard HTTP method names */
protected static final String METHOD_POST = "post";
protected static final String METHOD_GET = "get";
protected static final String METHOD_PUT = "put";
protected static final String METHOD_DELETE = "delete";
/** Test web script server */
private static TestWebScriptServer server = null;
protected static TestWebScriptServer getServer()
{
if (BaseWebScriptTest.server == null)
{
BaseWebScriptTest.server = TestWebScriptRepoServer.getTestServer();
}
return BaseWebScriptTest.server;
}
/**
* "GET" the url and check for the expected status code
*
* @param url
* @param expectedStatus
* @return
* @throws IOException
*/
protected MockHttpServletResponse getRequest(String url, int expectedStatus)
throws IOException
{
return sendRequest(METHOD_GET, url, expectedStatus, null, null);
}
/**
* "POST" the url and check for the expected status code
*
* @param url
* @param expectedStatus
* @return
* @throws IOException
*/
protected MockHttpServletResponse postRequest(String url, int expectedStatus, String body, String contentType)
throws IOException
{
return sendRequest(METHOD_POST, url, expectedStatus, body, contentType);
}
/**
*
* @param method
* @param url
* @param expectedStatus
* @return
* @throws IOException
*/
private MockHttpServletResponse sendRequest(String method, String url, int expectedStatus, String body, String contentType)
throws IOException
{
MockHttpServletResponse response = BaseWebScriptTest.getServer().submitRequest(method, url, new HashMap<String, String>(), body, contentType);
if (expectedStatus != response.getStatus())
{
if (response.getStatus() == 500)
{
System.out.println(response.getContentAsString());
}
fail("The expected status code (" + expectedStatus + ") was not returned.");
}
return response;
}
}

View File

@@ -0,0 +1,850 @@
/*
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantDeployer;
import org.alfresco.repo.tenant.TenantDeployerService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.scripts.ScriptContent;
import org.alfresco.web.scripts.ScriptLoader;
import org.alfresco.web.scripts.Store;
import org.alfresco.web.scripts.WebScript;
import org.alfresco.web.scripts.WebScriptException;
import freemarker.cache.TemplateLoader;
/**
* Repository based Web Script Store
*
* @author davidc
*/
public class RepoStore implements Store, TenantDeployer
{
protected boolean mustExist = false;
protected StoreRef repoStore;
protected String repoPath;
protected Map<String, NodeRef> baseNodeRefs;
// dependencies
protected RetryingTransactionHelper retryingTransactionHelper;
protected SearchService searchService;
protected NodeService nodeService;
protected ContentService contentService;
protected FileFolderService fileService;
protected NamespaceService namespaceService;
protected PermissionService permissionService;
protected TenantDeployerService tenantDeployerService;
/**
* Sets helper that provides transaction callbacks
*/
public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
/**
* Sets the search service
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* Sets the node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Sets the content service
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* Sets the file service
*/
public void setFileFolderService(FileFolderService fileService)
{
this.fileService = fileService;
}
/**
* Sets the namespace service
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* Sets the permission service
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* Sets the tenant deployer service
*/
public void setTenantDeployerService(TenantDeployerService tenantDeployerService)
{
this.tenantDeployerService = tenantDeployerService;
}
/**
* Sets whether the repo store must exist
*
* @param mustExist
*/
public void setMustExist(boolean mustExist)
{
this.mustExist = mustExist;
}
/**
* Sets the repo store
*/
public void setStore(String repoStore)
{
this.repoStore = new StoreRef(repoStore);
}
/**
* Sets the repo path
*
* @param repoPath repoPath
*/
public void setPath(String repoPath)
{
this.repoPath = repoPath;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#init()
* @see org.alfresco.repo.tenant.TenantDeployer#init()
*/
public void init()
{
if (baseNodeRefs == null)
{
baseNodeRefs = new HashMap<String, NodeRef>(1);
}
getBaseNodeRef();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#destroy()
*/
public void destroy()
{
baseNodeRefs.remove(tenantDeployerService.getCurrentUserDomain());
}
private NodeRef getBaseNodeRef()
{
String tenantDomain = tenantDeployerService.getCurrentUserDomain();
NodeRef baseNodeRef = baseNodeRefs.get(tenantDomain);
if (baseNodeRef == null)
{
baseNodeRef = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>()
{
public NodeRef doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Exception
{
String query = "PATH:\"" + repoPath + "\"";
ResultSet resultSet = searchService.query(repoStore, SearchService.LANGUAGE_LUCENE, query);
if (resultSet.length() == 1)
{
return resultSet.getNodeRef(0);
}
else if (mustExist)
{
throw new WebScriptException("Web Script Store " + repoStore.toString() + repoPath + " must exist; it was not found");
}
return null;
}
});
}
}, AuthenticationUtil.getSystemUserName());
// TODO clear on deleteTenant
baseNodeRefs.put(tenantDomain, baseNodeRef);
}
return baseNodeRef;
}
private String getBaseDir()
{
return getPath(getBaseNodeRef());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#exists()
*/
public boolean exists()
{
return (getBaseNodeRef() != null);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#getBasePath()
*/
public String getBasePath()
{
return repoStore.toString() + repoPath;
}
/**
* Gets the display path for the specified node
*
* @param nodeRef
* @return display path
*/
protected String getPath(NodeRef nodeRef)
{
return nodeService.getPath(nodeRef).toDisplayPath(nodeService, permissionService) +
"/" + nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
}
/**
* Gets the node ref for the specified path within this repo store
*
* @param documentPath
* @return node ref
*/
protected NodeRef findNodeRef(String documentPath)
{
NodeRef node = null;
try
{
String[] pathElements = documentPath.split("/");
List<String> pathElementsList = Arrays.asList(pathElements);
FileInfo file = fileService.resolveNamePath(getBaseNodeRef(), pathElementsList);
node = file.getNodeRef();
}
catch (FileNotFoundException e)
{
// NOTE: return null
}
return node;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#getScriptDocumentPaths(org.alfresco.web.scripts.WebScript)
*/
public String[] getScriptDocumentPaths(final WebScript script)
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<String[]>()
{
public String[] doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<String[]>()
{
public String[] execute() throws Exception
{
int baseDirLength = getBaseDir().length() +1;
List<String> documentPaths = null;
String scriptPath = script.getDescription().getScriptPath();
NodeRef scriptNodeRef = (scriptPath.length() == 0) ? getBaseNodeRef() : findNodeRef(scriptPath);
if (scriptNodeRef != null)
{
org.alfresco.service.cmr.repository.Path repoScriptPath = nodeService.getPath(scriptNodeRef);
String id = script.getDescription().getId().substring(scriptPath.length() + (scriptPath.length() > 0 ? 1 : 0));
String query = "+PATH:\"" + repoScriptPath.toPrefixString(namespaceService) + "//*\" +QNAME:" + id + "*";
ResultSet resultSet = searchService.query(repoStore, SearchService.LANGUAGE_LUCENE, query);
documentPaths = new ArrayList<String>(resultSet.length());
List<NodeRef> nodes = resultSet.getNodeRefs();
for (NodeRef nodeRef : nodes)
{
String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
if (name.startsWith(id))
{
String nodeDir = getPath(nodeRef);
String documentPath = nodeDir.substring(baseDirLength);
documentPaths.add(documentPath);
}
}
}
return documentPaths != null ? documentPaths.toArray(new String[documentPaths.size()]) : new String[0];
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#getDescriptionDocumentPaths()
*/
public String[] getDescriptionDocumentPaths()
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<String[]>()
{
public String[] doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<String[]>()
{
public String[] execute() throws Exception
{
int baseDirLength = getBaseDir().length() +1;
String query = "+PATH:\"" + repoPath + "//*\" +QNAME:*.desc.xml";
ResultSet resultSet = searchService.query(repoStore, SearchService.LANGUAGE_LUCENE, query);
List<String> documentPaths = new ArrayList<String>(resultSet.length());
List<NodeRef> nodes = resultSet.getNodeRefs();
for (NodeRef nodeRef : nodes)
{
String nodeDir = getPath(nodeRef);
if (nodeDir.endsWith(".desc.xml"))
{
String documentPath = nodeDir.substring(baseDirLength);
documentPaths.add(documentPath);
}
}
return documentPaths.toArray(new String[documentPaths.size()]);
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#getAllDocumentPaths()
*/
public String[] getAllDocumentPaths()
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<String[]>()
{
public String[] doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<String[]>()
{
public String[] execute() throws Exception
{
int baseDirLength = getBaseDir().length() +1;
String query = "+PATH:\"" + repoPath + "//*\" +TYPE:\"{http://www.alfresco.org/model/content/1.0}content\"";
ResultSet resultSet = searchService.query(repoStore, SearchService.LANGUAGE_LUCENE, query);
List<String> documentPaths = new ArrayList<String>(resultSet.length());
List<NodeRef> nodes = resultSet.getNodeRefs();
for (NodeRef nodeRef : nodes)
{
String nodeDir = getPath(nodeRef);
documentPaths.add(nodeDir.substring(baseDirLength));
}
return documentPaths.toArray(new String[documentPaths.size()]);
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#lastModified(java.lang.String)
*/
public long lastModified(final String documentPath) throws IOException
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Long>()
{
public Long doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Long>()
{
public Long execute() throws Exception
{
ContentReader reader = contentService.getReader(
findNodeRef(documentPath), ContentModel.PROP_CONTENT);
return reader.getLastModified();
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#hasDocument(java.lang.String)
*/
public boolean hasDocument(final String documentPath)
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Boolean>()
{
public Boolean doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Boolean>()
{
public Boolean execute() throws Exception
{
NodeRef nodeRef = findNodeRef(documentPath);
return (nodeRef != null);
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#getDescriptionDocument(java.lang.String)
*/
public InputStream getDocument(final String documentPath)
throws IOException
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<InputStream>()
{
public InputStream doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<InputStream>()
{
public InputStream execute() throws Exception
{
NodeRef nodeRef = findNodeRef(documentPath);
if (nodeRef == null)
{
throw new IOException("Document " + documentPath + " does not exist.");
}
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
if (reader == null || !reader.exists())
{
throw new IOException("Failed to read content at " + documentPath + " (content reader does not exist)");
}
return reader.getContentInputStream();
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#createDocument(java.lang.String, java.lang.String)
*/
public void createDocument(String documentPath, String content) throws IOException
{
String[] pathElements = documentPath.split("/");
String[] folderElements = new String[pathElements.length -1];
System.arraycopy(pathElements, 0, folderElements, 0, pathElements.length -1);
List<String> folderElementsList = Arrays.asList(folderElements);
// create folder
FileInfo pathInfo;
if (folderElementsList.size() == 0)
{
pathInfo = fileService.getFileInfo(getBaseNodeRef());
}
else
{
pathInfo = FileFolderServiceImpl.makeFolders(fileService, getBaseNodeRef(), folderElementsList, ContentModel.TYPE_FOLDER);
}
// create file
String fileName = pathElements[pathElements.length -1];
if (fileService.searchSimple(pathInfo.getNodeRef(), fileName) != null)
{
throw new IOException("Document " + documentPath + " already exists");
}
FileInfo fileInfo = fileService.create(pathInfo.getNodeRef(), fileName, ContentModel.TYPE_CONTENT);
ContentWriter writer = fileService.getWriter(fileInfo.getNodeRef());
writer.putContent(content);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#updateDocument(java.lang.String, java.lang.String)
*/
public void updateDocument(String documentPath, String content) throws IOException
{
String[] pathElements = documentPath.split("/");
// get parent folder
NodeRef parentRef;
if (pathElements.length == 1)
{
parentRef = getBaseNodeRef();
}
else
{
parentRef = findNodeRef(documentPath.substring(0, documentPath.lastIndexOf('/')));
}
// update file
String fileName = pathElements[pathElements.length -1];
if (fileService.searchSimple(parentRef, fileName) == null)
{
throw new IOException("Document " + documentPath + " does not exists");
}
FileInfo fileInfo = fileService.create(parentRef, fileName, ContentModel.TYPE_CONTENT);
ContentWriter writer = fileService.getWriter(fileInfo.getNodeRef());
writer.putContent(content);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#getTemplateLoader()
*/
public TemplateLoader getTemplateLoader()
{
return new RepoTemplateLoader();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Store#getScriptLoader()
*/
public ScriptLoader getScriptLoader()
{
return new RepoScriptLoader();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant()
*/
public void onEnableTenant()
{
init();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant()
*/
public void onDisableTenant()
{
destroy();
}
/**
* Repository path based template loader
*
* @author davidc
*/
private class RepoTemplateLoader implements TemplateLoader
{
/* (non-Javadoc)
* @see freemarker.cache.TemplateLoader#findTemplateSource(java.lang.String)
*/
public Object findTemplateSource(final String name)
throws IOException
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
RepoTemplateSource source = null;
NodeRef nodeRef = findNodeRef(name);
if (nodeRef != null)
{
source = new RepoTemplateSource(nodeRef);
}
return source;
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see freemarker.cache.TemplateLoader#getLastModified(java.lang.Object)
*/
public long getLastModified(Object templateSource)
{
return ((RepoTemplateSource)templateSource).lastModified();
}
/* (non-Javadoc)
* @see freemarker.cache.TemplateLoader#getReader(java.lang.Object, java.lang.String)
*/
public Reader getReader(Object templateSource, String encoding) throws IOException
{
return ((RepoTemplateSource)templateSource).getReader();
}
/* (non-Javadoc)
* @see freemarker.cache.TemplateLoader#closeTemplateSource(java.lang.Object)
*/
public void closeTemplateSource(Object arg0) throws IOException
{
}
}
/**
* Repository (content) node template source
*
* @author davidc
*/
private class RepoTemplateSource
{
protected final NodeRef nodeRef;
/**
* Construct
*
* @param ref
*/
private RepoTemplateSource(NodeRef ref)
{
this.nodeRef = ref;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object o)
{
if (o instanceof RepoTemplateSource)
{
return nodeRef.equals(((RepoTemplateSource)o).nodeRef);
}
else
{
return false;
}
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode()
{
return nodeRef.hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString()
{
return nodeRef.toString();
}
/**
* Gets the last modified time of the content
*
* @return last modified time
*/
public long lastModified()
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Long>()
{
public Long doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Long>()
{
public Long execute() throws Exception
{
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
return reader.getLastModified();
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/**
* Gets the content reader
*
* @return content reader
* @throws IOException
*/
public Reader getReader() throws IOException
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Reader>()
{
public Reader doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Reader>()
{
public Reader execute() throws Exception
{
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
return new InputStreamReader(reader.getContentInputStream(), reader.getEncoding());
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
}
/**
* Repository path based script loader
*
* @author davidc
*/
private class RepoScriptLoader implements ScriptLoader
{
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptLoader#getScriptLocation(java.lang.String)
*/
public ScriptContent getScript(final String path)
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<ScriptContent>()
{
public ScriptContent doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<ScriptContent>()
{
public ScriptContent execute() throws Exception
{
ScriptContent location = null;
NodeRef nodeRef = findNodeRef(path);
if (nodeRef != null)
{
location = new RepoScriptContent(path, nodeRef);
}
return location;
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
}
/**
* Repo path script location
*
* @author davidc
*/
private class RepoScriptContent implements ScriptContent
{
protected String path;
protected NodeRef nodeRef;
/**
* Construct
*
* @param location
*/
public RepoScriptContent(String path, NodeRef nodeRef)
{
this.path = path;
this.nodeRef = nodeRef;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#getInputStream()
*/
public InputStream getInputStream()
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<InputStream>()
{
public InputStream doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<InputStream>()
{
public InputStream execute() throws Exception
{
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
return reader.getContentInputStream();
}
});
}
}, AuthenticationUtil.getSystemUserName());
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#getReader()
*/
public Reader getReader()
{
ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
try
{
return new InputStreamReader(getInputStream(), reader.getEncoding());
}
catch (UnsupportedEncodingException e)
{
throw new AlfrescoRuntimeException("Unsupported Encoding", e);
}
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptContent#getPath()
*/
public String getPath()
{
return repoStore + getBaseDir() + "/" + path;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptContent#getPathDescription()
*/
public String getPathDescription()
{
return "/" + path + " (in repository store " + repoStore.toString() + getBaseDir() + ")";
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptContent#isSecure()
*/
public boolean isSecure()
{
return false;
}
}
}

View File

@@ -0,0 +1,484 @@
/*
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.TenantDeployer;
import org.alfresco.repo.tenant.TenantDeployerService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.util.AbstractLifecycleBean;
import org.alfresco.web.scripts.WebScriptException;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
/**
* Provision of Repository Context
*
* @author davidc
*/
public class Repository implements ApplicationContextAware, ApplicationListener, TenantDeployer
{
private ProcessorLifecycle lifecycle = new ProcessorLifecycle();
// dependencies
private RetryingTransactionHelper retryingTransactionHelper;
private NamespaceService namespaceService;
private SearchService searchService;
private NodeService nodeService;
private FileFolderService fileFolderService;
private PersonService personService;
private AVMService avmService;
private TenantDeployerService tenantDeployerService;
// company home
private StoreRef companyHomeStore;
private String companyHomePath;
private Map<String, NodeRef> companyHomeRefs;
/**
* Sets the Company Home Store
*
* @param companyHomeStore
*/
public void setCompanyHomeStore(String companyHomeStore)
{
this.companyHomeStore = new StoreRef(companyHomeStore);
}
/**
* Sets the Company Home Path
*
* @param companyHomePath
*/
public void setCompanyHomePath(String companyHomePath)
{
this.companyHomePath = companyHomePath;
}
/**
* Sets helper that provides transaction callbacks
*/
public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
/**
* Sets the namespace service
*
* @param namespaceService
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* Sets the search service
*
* @param searchService
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* Sets the node service
*
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Sets the file folder service
*
* @param nodeService
*/
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
/**
* Sets the person service
*
* @param personService
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* Sets the tenant deployer service
*
* @param tenantDeployerService
*/
public void setTenantDeployerService(TenantDeployerService tenantDeployerService)
{
this.tenantDeployerService = tenantDeployerService;
}
/**
* Sets the AVM service
*
* @param avmService
*/
public void setAvmService(AVMService avmService)
{
this.avmService = avmService;
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
lifecycle.setApplicationContext(applicationContext);
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(ApplicationEvent event)
{
lifecycle.onApplicationEvent(event);
}
/**
* Hooks into Spring Application Lifecycle
*/
private class ProcessorLifecycle extends AbstractLifecycleBean
{
@Override
protected void onBootstrap(ApplicationEvent event)
{
initContext();
}
@Override
protected void onShutdown(ApplicationEvent event)
{
}
}
/**
* Initialise Repository Context
*/
protected void initContext()
{
tenantDeployerService.register(this);
if (companyHomeRefs == null)
{
companyHomeRefs = new HashMap<String, NodeRef>(1);
}
getCompanyHome();
}
/**
* Gets the root home of the company home store
*
* @return root node ref
*/
public NodeRef getRootHome()
{
return nodeService.getRootNode(companyHomeStore);
}
/**
* Gets the Company Home
*
* @return company home node ref
*/
public NodeRef getCompanyHome()
{
String tenantDomain = tenantDeployerService.getCurrentUserDomain();
NodeRef companyHomeRef = companyHomeRefs.get(tenantDomain);
if (companyHomeRef == null)
{
companyHomeRef = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
{
public NodeRef doWork() throws Exception
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Exception
{
List<NodeRef> refs = searchService.selectNodes(nodeService.getRootNode(companyHomeStore), companyHomePath, null, namespaceService, false);
if (refs.size() != 1)
{
throw new IllegalStateException("Invalid company home path: " + companyHomePath + " - found: " + refs.size());
}
return refs.get(0);
}
});
}
}, AuthenticationUtil.getSystemUserName());
companyHomeRefs.put(tenantDomain, companyHomeRef);
}
return companyHomeRef;
}
/**
* Gets the currently authenticated person
*
* @return person node ref
*/
public NodeRef getPerson()
{
NodeRef person = null;
String currentUserName = AuthenticationUtil.getCurrentUserName();
if (personService.personExists(currentUserName))
{
person = personService.getPerson(currentUserName);
}
return person;
}
/**
* Gets the user home of the currently authenticated person
*
* @param person person
* @return user home of person
*/
public NodeRef getUserHome(NodeRef person)
{
return (NodeRef)nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER);
}
/**
* Helper to convert a Web Script Request URL to a Node Ref
*
* 1) Node - {store_type}/{store_id}/{node_id}
*
* Resolve to node via its Node Reference.
*
* 2) Path - {store_type}/{store_id}/{path}
*
* Resolve to node via its display path.
*
* 3) AVM Path - {store_id}/{path}
*
* Resolve to AVM node via its display path
*
* 4) QName - {store_type}/{store_id}/{child_qname_path} TODO: Implement
*
* Resolve to node via its child qname path.
*
* @param referenceType one of node, path, avmpath or qname
* @return reference array of reference segments (as described above for each reference type)
*/
public NodeRef findNodeRef(String referenceType, String[] reference)
{
NodeRef nodeRef = null;
if (referenceType.equals("avmpath"))
{
if (reference.length == 0)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Reference " + Arrays.toString(reference) + " is not properly formed");
}
String path = reference[0] + ":/";
if (reference.length > 1)
{
Object[] pathElements = ArrayUtils.subarray(reference, 1, reference.length);
path += StringUtils.join(pathElements, "/");
}
AVMNodeDescriptor nodeDesc = avmService.lookup(-1, path);
if (nodeDesc != null)
{
nodeRef = AVMNodeConverter.ToNodeRef(-1, path);
}
}
else
{
// construct store reference
if (reference.length < 3)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Reference " + Arrays.toString(reference) + " is not properly formed");
}
StoreRef storeRef = new StoreRef(reference[0], reference[1]);
if (nodeService.exists(storeRef))
{
if (referenceType.equals("node"))
{
// find the node the rest of the path is relative to
NodeRef relRef = new NodeRef(storeRef, reference[2]);
if (nodeService.exists(relRef))
{
// are there any relative path elements to process?
if (reference.length == 3 || reference.length == 4)
{
// just the NodeRef can be specified
nodeRef = relRef;
}
else
{
// process optional path elements
List<String> paths = new ArrayList<String>(reference.length - 3);
for (int i=3; i<reference.length; i++)
{
paths.add(reference[i]);
}
try
{
NodeRef parentRef = nodeService.getPrimaryParent(relRef).getParentRef();
FileInfo fileInfo = fileFolderService.resolveNamePath(parentRef, paths);
nodeRef = fileInfo.getNodeRef();
}
catch (FileNotFoundException e)
{
// NOTE: return null node ref
}
}
}
}
else if (referenceType.equals("path"))
{
// NOTE: special case for avm based path
if (reference[0].equals(StoreRef.PROTOCOL_AVM))
{
String path = reference[1] + ":/";
if (reference.length > 2)
{
Object[] pathElements = ArrayUtils.subarray(reference, 2, reference.length);
path += StringUtils.join(pathElements, "/");
}
AVMNodeDescriptor nodeDesc = avmService.lookup(-1, path);
if (nodeDesc != null)
{
nodeRef = AVMNodeConverter.ToNodeRef(-1, path);
}
}
else
{
// TODO: Allow a root path to be specified - for now, hard-code to Company Home
//NodeRef rootNodeRef = nodeService.getRootNode(storeRef);
NodeRef rootNodeRef = getCompanyHome();
if (reference.length == 3)
{
nodeRef = rootNodeRef;
}
else
{
String[] path = new String[reference.length - /*2*/3];
System.arraycopy(reference, /*2*/3, path, 0, path.length);
try
{
FileInfo fileInfo = fileFolderService.resolveNamePath(rootNodeRef, Arrays.asList(path));
nodeRef = fileInfo.getNodeRef();
}
catch (FileNotFoundException e)
{
// NOTE: return null node ref
}
}
}
}
else
{
// TODO: Implement 'qname' style
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Web Script Node URL specified an invalid reference style of '" + referenceType + "'");
}
}
}
return nodeRef;
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant()
*/
public void onEnableTenant()
{
init();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant()
*/
public void onDisableTenant()
{
destroy();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#init()
*/
public void init()
{
initContext();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#destroy()
*/
public void destroy()
{
companyHomeRefs.remove(tenantDeployerService.getCurrentUserDomain());
}
}

View File

@@ -0,0 +1,393 @@
/*
* Copyright (C) 2005-2008 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantDeployer;
import org.alfresco.repo.tenant.TenantDeployerService;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.web.scripts.AbstractRuntimeContainer;
import org.alfresco.web.scripts.Authenticator;
import org.alfresco.web.scripts.Description;
import org.alfresco.web.scripts.Registry;
import org.alfresco.web.scripts.ServerModel;
import org.alfresco.web.scripts.WebScript;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
import org.alfresco.web.scripts.Description.RequiredAuthentication;
import org.alfresco.web.scripts.Description.RequiredTransaction;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectFactory;
/**
* Repository (server-tier) container for Web Scripts
*
* @author davidc
*/
public class RepositoryContainer extends AbstractRuntimeContainer implements TenantDeployer
{
// Logger
protected static final Log logger = LogFactory.getLog(RepositoryContainer.class);
/** Component Dependencies */
private Repository repository;
private RepositoryImageResolver imageResolver;
private RetryingTransactionHelper retryingTransactionHelper;
private AuthorityService authorityService;
private PermissionService permissionService;
private DescriptorService descriptorService;
private TenantDeployerService tenantDeployerService;
private ObjectFactory registryFactory;
private SimpleCache<String, Registry> webScriptsRegistryCache;
/**
* @param webScriptsRegistryCache
*/
public void setWebScriptsRegistryCache(SimpleCache<String, Registry> webScriptsRegistryCache)
{
this.webScriptsRegistryCache = webScriptsRegistryCache;
}
/**
* @param registryFactory
*/
public void setRegistryFactory(ObjectFactory registryFactory) {
this.registryFactory = registryFactory;
}
/**
* @param repository
*/
public void setRepository(Repository repository)
{
this.repository = repository;
}
/**
* @param imageResolver
*/
public void setRepositoryImageResolver(RepositoryImageResolver imageResolver)
{
this.imageResolver = imageResolver;
}
/**
* @param permissionService
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* @param retryingTransactionHelper
*/
public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
/**
* @param descriptorService
*/
public void setDescriptorService(DescriptorService descriptorService)
{
this.descriptorService = descriptorService;
}
/**
* @param authorityService
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* @param tenantDeployerService
*/
public void setTenantDeployerService(TenantDeployerService tenantDeployerService)
{
this.tenantDeployerService = tenantDeployerService;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Container#getDescription()
*/
public ServerModel getDescription()
{
return new RepositoryServerModel(descriptorService.getServerDescriptor());
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#getScriptParameters()
*/
public Map<String, Object> getScriptParameters()
{
Map<String, Object> params = new HashMap<String, Object>();
params.putAll(super.getScriptParameters());
addRepoParameters(params);
return params;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#getTemplateParameters()
*/
public Map<String, Object> getTemplateParameters()
{
Map<String, Object> params = new HashMap<String, Object>();
params.putAll(super.getTemplateParameters());
params.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver.getImageResolver());
addRepoParameters(params);
return params;
}
/**
* Add Repository specific parameters
*
* @param params
*/
private void addRepoParameters(Map<String, Object> params)
{
if (AlfrescoTransactionSupport.getTransactionId() != null && AuthenticationUtil.getCurrentAuthentication() != null)
{
NodeRef rootHome = repository.getRootHome();
if (rootHome != null && permissionService.hasPermission(rootHome, PermissionService.READ).equals(AccessStatus.ALLOWED))
{
params.put("roothome", rootHome);
}
NodeRef companyHome = repository.getCompanyHome();
if (companyHome != null && permissionService.hasPermission(companyHome, PermissionService.READ).equals(AccessStatus.ALLOWED))
{
params.put("companyhome", companyHome);
}
NodeRef person = repository.getPerson();
if (person != null && permissionService.hasPermission(companyHome, PermissionService.READ).equals(AccessStatus.ALLOWED))
{
params.put("person", person);
params.put("userhome", repository.getUserHome(person));
}
}
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.RuntimeContainer#executeScript(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse, org.alfresco.web.scripts.Authenticator)
*/
public void executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, Authenticator auth)
throws IOException
{
WebScript script = scriptReq.getServiceMatch().getWebScript();
Description desc = script.getDescription();
RequiredAuthentication required = desc.getRequiredAuthentication();
boolean isGuest = scriptReq.isGuest();
if (required == RequiredAuthentication.none)
{
// MT-context will pre-authenticate (see MTWebScriptAuthenticationFilter)
if (! AuthenticationUtil.isMtEnabled())
{
// TODO revisit - cleared here, in-lieu of WebClient clear
AuthenticationUtil.clearCurrentSecurityContext();
}
transactionedExecute(script, scriptReq, scriptRes);
}
else if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest)
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires user authentication; however, a guest has attempted access.");
}
else
{
String currentUser = null;
try
{
//
// Determine if user already authenticated
//
currentUser = AuthenticationUtil.getCurrentUserName();
if (logger.isDebugEnabled())
{
logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
logger.debug("Authentication required: " + required);
logger.debug("Guest login: " + isGuest);
}
//
// Apply appropriate authentication to Web Script invocation
//
if (auth == null || auth.authenticate(required, isGuest))
{
if (required == RequiredAuthentication.admin && !authorityService.hasAdminAuthority())
{
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access.");
}
// Execute Web Script
transactionedExecute(script, scriptReq, scriptRes);
}
}
finally
{
//
// Reset authentication for current thread
//
AuthenticationUtil.clearCurrentSecurityContext();
if (currentUser != null)
{
AuthenticationUtil.setCurrentUser(currentUser);
}
if (logger.isDebugEnabled())
logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
}
}
}
/**
* Execute script within required level of transaction
*
* @param scriptReq
* @param scriptRes
* @throws IOException
*/
protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes)
throws IOException
{
final Description description = script.getDescription();
if (description.getRequiredTransaction() == RequiredTransaction.none)
{
script.execute(scriptReq, scriptRes);
}
else
{
// encapsulate script within transaction
RetryingTransactionCallback<Object> work = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Begin transaction: " + description.getRequiredTransaction());
script.execute(scriptReq, scriptRes);
if (logger.isDebugEnabled())
logger.debug("End transaction: " + description.getRequiredTransaction());
return null;
}
};
if (description.getRequiredTransaction() == RequiredTransaction.required)
{
retryingTransactionHelper.doInTransaction(work);
}
else
{
retryingTransactionHelper.doInTransaction(work, false, true);
}
}
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#getRegistry()
*/
@Override
public Registry getRegistry()
{
String tenantDomain = tenantDeployerService.getCurrentUserDomain();
Registry registry = webScriptsRegistryCache.get(tenantDomain);
if (registry == null)
{
init();
registry = webScriptsRegistryCache.get(tenantDomain);
}
return registry;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.AbstractRuntimeContainer#reset()
*/
@Override
public void reset()
{
destroy();
init();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#onEnableTenant()
*/
public void onEnableTenant()
{
init();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#onDisableTenant()
*/
public void onDisableTenant()
{
destroy();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#init()
*/
public void init()
{
tenantDeployerService.register(this);
Registry registry = (Registry)registryFactory.getObject();
webScriptsRegistryCache.put(tenantDeployerService.getCurrentUserDomain(), registry);
super.reset();
}
/* (non-Javadoc)
* @see org.alfresco.repo.tenant.TenantDeployer#destroy()
*/
public void destroy()
{
webScriptsRegistryCache.remove(tenantDeployerService.getCurrentUserDomain());
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import javax.servlet.ServletContext;
import org.alfresco.service.cmr.repository.FileTypeImageSize;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.context.ServletContextAware;
/**
* Web Scripts Image Resolver
*
* @author davidc
*/
public class RepositoryImageResolver
implements ServletContextAware, InitializingBean
{
private ServletContext servletContext;
private TemplateImageResolver imageResolver;
/* (non-Javadoc)
* @see org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet.ServletContext)
*/
public void setServletContext(ServletContext context)
{
this.servletContext = context;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@SuppressWarnings("serial")
public void afterPropertiesSet()
throws Exception
{
this.imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, FileTypeImageSize size)
{
return FileTypeImageUtils.getFileTypeImage(servletContext, filename, size);
}
};
}
/**
* @return image resolver
*/
public TemplateImageResolver getImageResolver()
{
return this.imageResolver;
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import java.io.InputStream;
import java.io.Reader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.jscript.ValueConverter;
import org.alfresco.scripts.ScriptException;
import org.alfresco.service.cmr.repository.ScriptLocation;
import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.web.scripts.MultiScriptLoader;
import org.alfresco.web.scripts.ScriptContent;
import org.alfresco.web.scripts.ScriptLoader;
import org.alfresco.web.scripts.ScriptProcessor;
import org.alfresco.web.scripts.SearchPath;
import org.alfresco.web.scripts.Store;
import org.alfresco.web.scripts.WebScriptException;
/**
* Repository (server-tier) Web Script Processor
*
* @author davidc
*/
public class RepositoryScriptProcessor implements ScriptProcessor
{
// dependencies
protected ScriptService scriptService;
protected ScriptLoader scriptLoader;
protected SearchPath searchPath;
// Javascript Converter
private ValueConverter valueConverter = new ValueConverter();
/**
* @param scriptService
*/
public void setScriptService(ScriptService scriptService)
{
this.scriptService = scriptService;
}
/**
* @param searchPath
*/
public void setSearchPath(SearchPath searchPath)
{
this.searchPath = searchPath;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#findScript(java.lang.String)
*/
public ScriptContent findScript(String path)
{
return scriptLoader.getScript(path);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#executeScript(java.lang.String, java.util.Map)
*/
public Object executeScript(String path, Map<String, Object> model)
throws ScriptException
{
// locate script within web script stores
ScriptContent scriptContent = findScript(path);
if (scriptContent == null)
{
throw new WebScriptException("Unable to locate script " + path);
}
// execute script
return executeScript(scriptContent, model);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#executeScript(org.alfresco.web.scripts.ScriptContent, java.util.Map)
*/
public Object executeScript(ScriptContent content, Map<String, Object> model)
{
return scriptService.executeScript("javascript", new RepositoryScriptLocation(content), model);
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#unwrapValue(java.lang.Object)
*/
public Object unwrapValue(Object value)
{
return (value instanceof Serializable) ? valueConverter.convertValueForRepo((Serializable)value) : value;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ScriptProcessor#reset()
*/
public void reset()
{
init();
}
/**
* Register script loader from each Web Script Store with Script Processor
*/
private void init()
{
List<ScriptLoader> loaders = new ArrayList<ScriptLoader>();
for (Store apiStore : searchPath.getStores())
{
ScriptLoader loader = apiStore.getScriptLoader();
if (loader == null)
{
throw new WebScriptException("Unable to retrieve script loader for Web Script store " + apiStore.getBasePath());
}
loaders.add(loader);
}
scriptLoader = new MultiScriptLoader(loaders.toArray(new ScriptLoader[loaders.size()]));
}
/**
* Script Location Facade
*/
private static class RepositoryScriptLocation implements ScriptLocation
{
private ScriptContent content;
private RepositoryScriptLocation(ScriptContent content)
{
this.content = content;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#getInputStream()
*/
public InputStream getInputStream()
{
return content.getInputStream();
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#getReader()
*/
public Reader getReader()
{
return content.getReader();
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.repository.ScriptLocation#isSecure()
*/
public boolean isSecure()
{
return content.isSecure();
}
@Override
public String toString()
{
return content.getPathDescription();
}
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import org.alfresco.service.descriptor.Descriptor;
import org.alfresco.web.scripts.ServerModel;
/**
* Script / Template Model representing Repository Server meta-data
*
* @author davidc
*/
public class RepositoryServerModel implements ServerModel
{
private Descriptor serverDescriptor;
/**
* Construct
*
* @param serverDescriptor
*/
/*package*/ RepositoryServerModel(Descriptor serverDescriptor)
{
this.serverDescriptor = serverDescriptor;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getContainerName()
*/
public String getContainerName()
{
return "Repository";
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionMajor()
*/
public String getVersionMajor()
{
return serverDescriptor.getVersionMajor();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionMinor()
*/
public String getVersionMinor()
{
return serverDescriptor.getVersionMinor();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionRevision()
*/
public String getVersionRevision()
{
return serverDescriptor.getVersionRevision();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionLabel()
*/
public String getVersionLabel()
{
return serverDescriptor.getVersionLabel();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersionBuild()
*/
public String getVersionBuild()
{
return serverDescriptor.getVersionBuild();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getVersion()
*/
public String getVersion()
{
return serverDescriptor.getVersion();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getEdition()
*/
public String getEdition()
{
return serverDescriptor.getEdition();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.ServerModel#getSchema()
*/
public int getSchema()
{
return serverDescriptor.getSchema();
}
}

View File

@@ -0,0 +1,237 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.repo.template.FreeMarkerProcessor;
import org.alfresco.repo.template.QNameAwareObjectWrapper;
import org.alfresco.service.cmr.repository.ProcessorExtension;
import org.alfresco.util.AbstractLifecycleBean;
import org.alfresco.web.scripts.SearchPath;
import org.alfresco.web.scripts.Store;
import org.alfresco.web.scripts.TemplateProcessor;
import org.alfresco.web.scripts.WebScriptException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import freemarker.cache.MruCacheStorage;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
/**
* Repository (server-tier) Web Script Template Processor
*
* @author davidc
*/
public class RepositoryTemplateProcessor extends FreeMarkerProcessor
implements TemplateProcessor, ApplicationContextAware, ApplicationListener
{
private ProcessorLifecycle lifecycle = new ProcessorLifecycle();
protected SearchPath searchPath;
protected String defaultEncoding;
protected Configuration templateConfig;
protected FreeMarkerProcessor freeMarkerProcessor;
/* (non-Javadoc)
* @see org.alfresco.repo.template.FreeMarkerProcessor#setDefaultEncoding(java.lang.String)
*/
public void setDefaultEncoding(String defaultEncoding)
{
this.defaultEncoding = defaultEncoding;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.TemplateProcessor#getDefaultEncoding()
*/
public String getDefaultEncoding()
{
return this.defaultEncoding;
}
/**
* @param searchPath
*/
public void setSearchPath(SearchPath searchPath)
{
this.searchPath = searchPath;
}
/**
* Set the freemarker processor
*
* @param freeMarkerProcessor the free marker processor
*/
public void setFreeMarkerProcessor(FreeMarkerProcessor freeMarkerProcessor)
{
this.freeMarkerProcessor = freeMarkerProcessor;
}
/* (non-Javadoc)
* @see org.alfresco.repo.template.FreeMarkerProcessor#getConfig()
*/
@Override
protected Configuration getConfig()
{
return templateConfig;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.TemplateProcessor#reset()
*/
public void reset()
{
if (templateConfig != null)
{
templateConfig.clearTemplateCache();
}
initConfig();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.TemplateProcessor#hasTemplate(java.lang.String)
*/
public boolean hasTemplate(String templatePath)
{
boolean hasTemplate = false;
try
{
Template template = templateConfig.getTemplate(templatePath);
hasTemplate = (template != null);
}
catch(FileNotFoundException e)
{
// NOTE: return false as template is not found
}
catch(IOException e)
{
throw new WebScriptException("Failed to retrieve template " + templatePath, e);
}
return hasTemplate;
}
/**
* Initialise FreeMarker Configuration
*/
protected void initConfig()
{
Configuration config = new Configuration();
// setup template cache
config.setCacheStorage(new MruCacheStorage(20, 100));
config.setTemplateUpdateDelay(0);
// setup template loaders
List<TemplateLoader> loaders = new ArrayList<TemplateLoader>();
for (Store apiStore : searchPath.getStores())
{
TemplateLoader loader = apiStore.getTemplateLoader();
if (loader == null)
{
throw new WebScriptException("Unable to retrieve template loader for Web Script store " + apiStore.getBasePath());
}
loaders.add(loader);
}
MultiTemplateLoader loader = new MultiTemplateLoader(loaders.toArray(new TemplateLoader[loaders.size()]));
config.setTemplateLoader(loader);
// use our custom object wrapper that can deal with QNameMap objects directly
config.setObjectWrapper(new QNameAwareObjectWrapper());
// rethrow any exception so we can deal with them
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// turn off locale sensitive lookup - to save numerous wasted calls to nodeservice.exists()
config.setLocalizedLookup(false);
// set template encoding
if (defaultEncoding != null)
{
config.setDefaultEncoding(defaultEncoding);
}
// set output encoding
config.setOutputEncoding("UTF-8");
templateConfig = config;
}
/**
* Tempory fix to initialise this template processor with the freeMarker extensions expected by
* the templates.
*/
private void initProcessorExtensions()
{
for (ProcessorExtension processorExtension : this.freeMarkerProcessor.getProcessorExtensions())
{
this.registerProcessorExtension(processorExtension);
}
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
lifecycle.setApplicationContext(applicationContext);
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(ApplicationEvent event)
{
lifecycle.onApplicationEvent(event);
}
/**
* Hooks into Spring Application Lifecycle
*/
private class ProcessorLifecycle extends AbstractLifecycleBean
{
@Override
protected void onBootstrap(ApplicationEvent event)
{
initProcessorExtensions();
}
@Override
protected void onShutdown(ApplicationEvent event)
{
}
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.web.scripts.TestWebScriptServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Stand-alone Web Script Test Server
*
* @author davidc
*/
public class TestWebScriptRepoServer extends TestWebScriptServer
{
private RetryingTransactionHelper retryingTransactionHelper;
private AuthenticationService authenticationService;
/**
* Sets helper that provides transaction callbacks
*/
public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
/**
* @param authenticationService
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/**
* Main entry point.
*/
public static void main(String[] args)
{
try
{
TestWebScriptServer testServer = getTestServer();
testServer.rep();
}
catch(Throwable e)
{
StringWriter strWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(strWriter);
e.printStackTrace(printWriter);
System.out.println(strWriter.toString());
}
finally
{
System.exit(0);
}
}
/**
* Retrieve an instance of the TestWebScriptServer
*
* @return Test Server
*/
public static TestWebScriptServer getTestServer()
{
String[] CONFIG_LOCATIONS = new String[]
{
"classpath:alfresco/application-context.xml",
"classpath:alfresco/webscript-framework-application-context.xml",
"classpath:alfresco/web-scripts-application-context.xml",
"classpath:alfresco/web-scripts-application-context-test.xml"
};
ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS);
TestWebScriptServer testServer = (TestWebScriptRepoServer)context.getBean("webscripts.test");
return testServer;
}
/**
* Interpret a single command using the BufferedReader passed in for any data needed.
*
* @param line The unparsed command
* @return The textual output of the command.
*/
@Override
protected String interpretCommand(final String line)
throws IOException
{
try
{
if (username.startsWith("TICKET_"))
{
try
{
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
{
public Object execute() throws Exception
{
authenticationService.validate(username);
return null;
}
});
return executeCommand(line);
}
finally
{
authenticationService.clearCurrentSecurityContext();
}
}
}
catch(AuthenticationException e)
{
executeCommand("user admin");
}
// execute command in context of currently selected user
return AuthenticationUtil.runAs(new RunAsWork<String>()
{
@SuppressWarnings("synthetic-access")
public String doWork() throws Exception
{
return executeCommand(line);
}
}, username);
}
}

View File

@@ -0,0 +1,218 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
package org.alfresco.repo.web.scripts.bean;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.net.SocketException;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptResponse;
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* AVM Remote Store service.
*
* @see BaseRemoteStore for API methods.
*
* @author Kevin Roast
*/
public class AVMRemoteStore extends BaseRemoteStore
{
private static final Log logger = LogFactory.getLog(AVMRemoteStore.class);
private String rootPath;
private AVMService avmService;
/**
* @param rootPath the root path under which to process store requests
*/
public void setRootPath(String rootPath)
{
this.rootPath = rootPath;
}
/**
* @param avmService the AVMService to set
*/
public void setAvmService(AVMService avmService)
{
this.avmService = avmService;
}
/**
* Gets the last modified timestamp for the document.
*
* @param path document path to an existing document
*/
@Override
protected void lastModified(WebScriptResponse res, String path)
throws IOException
{
String avmPath = buildAVMPath(path);
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc == null)
{
throw new WebScriptException("Unable to locate AVM file: " + avmPath);
}
Writer out = res.getWriter();
out.write(Long.toString(desc.getModDate()));
out.close();
}
/* (non-Javadoc)
* @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#getDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String)
*/
@Override
protected void getDocument(WebScriptResponse res, String path) throws IOException
{
String avmPath = buildAVMPath(path);
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc == null)
{
throw new WebScriptException("Unable to locate file: " + avmPath);
}
ContentReader reader = this.avmService.getContentReader(-1, avmPath);
if (reader == null)
{
throw new WebScriptException("No content found for AVM file: " + avmPath);
}
// establish mimetype
String mimetype = reader.getMimetype();
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MimetypeMap.MIMETYPE_BINARY;
int extIndex = path.lastIndexOf('.');
if (extIndex != -1)
{
String ext = path.substring(extIndex + 1);
String mt = this.mimetypeService.getMimetypesByExtension().get(ext);
if (mt != null)
{
mimetype = mt;
}
}
}
// set mimetype for the content and the character encoding + length for the stream
WebScriptServletResponse httpRes = (WebScriptServletResponse)res;
httpRes.setContentType(mimetype);
httpRes.getHttpServletResponse().setCharacterEncoding(reader.getEncoding());
httpRes.getHttpServletResponse().setDateHeader("Last-Modified", desc.getModDate());
httpRes.setHeader("Content-Length", Long.toString(reader.getSize()));
// get the content and stream directly to the response output stream
// assuming the repository is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
try
{
reader.getContent(res.getOutputStream());
}
catch (SocketException e1)
{
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + avmPath + "\n\tcontent: " + reader);
}
catch (ContentIOException e2)
{
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + avmPath + "\n\tcontent: " + reader);
}
}
/* (non-Javadoc)
* @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#hasDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String)
*/
@Override
protected void hasDocument(WebScriptResponse res, String path) throws IOException
{
String avmPath = buildAVMPath(path);
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
Writer out = res.getWriter();
out.write(Boolean.toString(desc != null));
out.close();
}
/* (non-Javadoc)
* @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#createDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream)
*/
@Override
protected void createDocument(WebScriptResponse res, String path, InputStream content)
{
String avmPath = buildAVMPath(path);
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc != null)
{
throw new WebScriptException("Unable to create, file already exists: " + avmPath);
}
String[] parts = AVMNodeConverter.SplitBase(avmPath);
this.avmService.createFile(parts[0], parts[1], content);
}
/* (non-Javadoc)
* @see org.alfresco.repo.web.scripts.bean.BaseRemoteStore#updateDocument(org.alfresco.web.scripts.WebScriptResponse, java.lang.String, java.io.InputStream)
*/
@Override
protected void updateDocument(WebScriptResponse res, String path, InputStream content)
{
String avmPath = buildAVMPath(path);
AVMNodeDescriptor desc = this.avmService.lookup(-1, avmPath);
if (desc == null)
{
throw new WebScriptException("Unable to locate file for update: " + avmPath);
}
ContentWriter writer = this.avmService.getContentWriter(avmPath);
writer.putContent(content);
}
/**
* @param path root path relative
*
* @return full AVM path to document including store and root path components
*/
private String buildAVMPath(String path)
{
return this.store + ":/" + this.rootPath + "/" + path;
}
}

View File

@@ -0,0 +1,253 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
package org.alfresco.repo.web.scripts.bean;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.web.scripts.AbstractWebScript;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
import org.alfresco.web.scripts.servlet.WebScriptServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Remote Store service.
*
* Responsible for providing remote HTTP based access to a store. Designed to be accessed
* from a web-tier application to remotely mirror a WebScript Store instance.
*
* Request format:
* <servicepath>/<method>/<path>
*
* Example:
* /service/remotestore/lastmodified/sites/xyz/pages/page.xml
*
* where:
* /service/remotestore -> service path
* /lastmodified -> method name
* /sites/../page.xml -> document path
*
* Note: path is relative to the root path as configured for this webscript bean
*
* For content create and update the request should be POSTed and the content sent as the
* payload of the request content.
*
* Supported method API:
* GET lastmodified -> return long timestamp of a document
* GET has -> return true/false of existence for a document
* GET get -> return document content - in addition the usual HTTP headers for the
* character encoding, content type, length and modified date will be supplied
* POST create -> create a new document with request content payload
* POST update -> update an existing document with request content payload
*
* @author Kevin Roast
*/
public abstract class BaseRemoteStore extends AbstractWebScript
{
private static final Log logger = LogFactory.getLog(BaseRemoteStore.class);
protected String store;
protected ContentService contentService;
protected MimetypeService mimetypeService;
/**
* @param store the store name of the store to process document requests against
*/
public void setStore(String store)
{
this.store = store;
}
/**
* @param contentService the ContentService to set
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* @param mimetypeService the MimetypeService to set
*/
public void setMimetypeService(MimetypeService mimetypeService)
{
this.mimetypeService = mimetypeService;
}
/**
* Execute the webscript based on the request parameters
*/
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
{
// NOTE: This web script must be executed in a HTTP Servlet environment
if (!(req instanceof WebScriptServletRequest))
{
throw new WebScriptException("Remote Store access must be executed in HTTP Servlet environment");
}
HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest();
// break down and validate the request - expecting method name and document path
String extPath = req.getExtensionPath();
String[] extParts = extPath == null ? new String[0] : extPath.split("/");
if (extParts.length < 1)
{
throw new WebScriptException("Remote Store expecting method name.");
}
if (extParts.length < 2)
{
throw new WebScriptException("Remote Store expecting document path.");
}
// build path as a string and as a list of path elements
String path = req.getExtensionPath().substring(extParts[0].length() + 1);
if (logger.isDebugEnabled())
logger.debug("Remote store method: " + extParts[0] + " path: " + path);
// TODO: support storeref name override as argument (i.e. for AVM virtualisation)
try
{
// generate enum from string method name - so we can use a fast switch table lookup
APIMethod method = APIMethod.valueOf(extParts[0].toUpperCase());
switch (method)
{
case LASTMODIFIED:
lastModified(res, path);
break;
case HAS:
hasDocument(res, path);
break;
case GET:
getDocument(res, path);
break;
case CREATE:
createDocument(res, path, httpReq.getInputStream());
break;
case UPDATE:
updateDocument(res, path, httpReq.getInputStream());
break;
}
}
catch (IllegalArgumentException enumErr)
{
throw new WebScriptException("Unknown method specified to remote store API: " + extParts[0]);
}
catch (IOException ioErr)
{
throw new WebScriptException("Error during remote store API: " + ioErr.getMessage());
}
}
/**
* Helper to break down webscript extension path into path component elements
*/
protected List<String> getPathParts(String[] extPaths)
{
List<String> pathParts = new ArrayList<String>(extPaths.length - 1);
for (int i=1; i<extPaths.length; i++)
{
pathParts.add(extPaths[i]);
}
return pathParts;
}
/**
* Gets the last modified timestamp for the document.
*
* @param path document path to an existing document
*/
protected abstract void lastModified(WebScriptResponse res, String path)
throws IOException;
/**
* Determines if the document exists
*
* @param path document path
* @return true => exists, false => does not exist
*/
protected abstract void hasDocument(WebScriptResponse res, String path)
throws IOException;
/**
* Gets a document
*
* @param path document path
* @return input stream onto document
*
* @throws IOException if the document does not exist in the store
*/
protected abstract void getDocument(WebScriptResponse res, String path)
throws IOException;
/**
* Creates a document.
*
* @param path document path
* @param content content of the document to write
*
* @throws IOException if the document already exists or the create fails
*/
protected abstract void createDocument(WebScriptResponse res, String path, InputStream content);
/**
* Updates an existing document.
*
* @param path document path
* @param content content to update the document with
*
* @throws IOException if the document does not exist or the update fails
*/
protected abstract void updateDocument(WebScriptResponse res, String path, InputStream content);
/**
* Enum representing the API method on the Store.
*/
private enum APIMethod
{
LASTMODIFIED,
HAS,
GET,
CREATE,
UPDATE
};
}

View File

@@ -0,0 +1,283 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.io.IOException;
import java.net.SocketException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.web.scripts.Repository;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.URLEncoder;
import org.alfresco.web.scripts.AbstractWebScript;
import org.alfresco.web.scripts.Cache;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
import org.alfresco.web.scripts.servlet.WebScriptServletRequest;
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Content Retrieval Service
*
* Stream content from the Repository.
*
* @author davidc
*/
public class ContentGet extends AbstractWebScript
{
// Logger
private static final Log logger = LogFactory.getLog(ContentGet.class);
private static final String NODE_URL = "/api/node/content/{0}/{1}/{2}/{3}";
// Component dependencies
private Repository repository;
private NamespaceService namespaceService;
private PermissionService permissionService;
private NodeService nodeService;
private ContentService contentService;
private MimetypeService mimetypeService;
/**
* @param repository
*/
public void setRepository(Repository repository)
{
this.repository = repository;
}
/**
* @param namespaceService
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param permissionService
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param contentService
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* @param mimetypeService
*/
public void setMimetypeService(MimetypeService mimetypeService)
{
this.mimetypeService = mimetypeService;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
public void execute(WebScriptRequest req, WebScriptResponse res)
throws IOException
{
// NOTE: This web script must be executed in a HTTP Servlet environment
if (!(req instanceof WebScriptServletRequest))
{
throw new WebScriptException("Content retrieval must be executed in HTTP Servlet environment");
}
HttpServletRequest httpReq = ((WebScriptServletRequest)req).getHttpServletRequest();
HttpServletResponse httpRes = ((WebScriptServletResponse)res).getHttpServletResponse();
// convert web script URL to node reference in Repository
String match = req.getServiceMatch().getPath();
String[] matchParts = match.split("/");
String extensionPath = req.getExtensionPath();
String[] extParts = extensionPath == null ? new String[1] : extensionPath.split("/");
String[] path = new String[extParts.length -1];
System.arraycopy(extParts, 1, path, 0, extParts.length -1);
NodeRef nodeRef = repository.findNodeRef(matchParts[2], path);
if (nodeRef == null)
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path));
}
// determine content property
QName propertyQName = ContentModel.PROP_CONTENT;
String contentPart = extParts[0];
if (contentPart.length() > 0 && contentPart.charAt(0) == ';')
{
if (contentPart.length() < 2)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Content property malformed");
}
String propertyName = contentPart.substring(1);
if (propertyName.length() > 0)
{
propertyQName = QName.createQName(propertyName, namespaceService);
}
}
// determine attachment
boolean attach = Boolean.valueOf(req.getParameter("a"));
if (logger.isDebugEnabled())
logger.debug("Retrieving content from node ref " + nodeRef.toString() + " (property: " + propertyQName.toString() + ") (attach: " + attach + ")");
// check that the user has at least READ_CONTENT access - else redirect to the login page
if (permissionService.hasPermission(nodeRef, PermissionService.READ_CONTENT) == AccessStatus.DENIED)
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Permission denied");
}
// check If-Modified-Since header and set Last-Modified header as appropriate
Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
long modifiedSince = httpReq.getDateHeader("If-Modified-Since");
if (modifiedSince > 0L)
{
// round the date to the ignore millisecond value which is not supplied by header
long modDate = (modified.getTime() / 1000L) * 1000L;
if (modDate <= modifiedSince)
{
httpRes.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
}
// handle attachment
if (attach == true)
{
// set header based on filename - will force a Save As from the browse if it doesn't recognize it
// this is better than the default response of the browser trying to display the contents
httpRes.setHeader("Content-Disposition", "attachment");
}
// get the content reader
ContentReader reader = contentService.getReader(nodeRef, propertyQName);
if (reader == null || !reader.exists())
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to locate content for node ref " + nodeRef + " (property: " + propertyQName.toString() + ")");
}
// establish mimetype
String mimetype = reader.getMimetype();
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MimetypeMap.MIMETYPE_BINARY;
int extIndex = extensionPath.lastIndexOf('.');
if (extIndex != -1)
{
String ext = extensionPath.substring(extIndex + 1);
String mt = mimetypeService.getMimetypesByExtension().get(ext);
if (mt != null)
{
mimetype = mt;
}
}
}
// set mimetype for the content and the character encoding + length for the stream
httpRes.setContentType(mimetype);
httpRes.setCharacterEncoding(reader.getEncoding());
httpRes.setHeader("Content-Length", Long.toString(reader.getSize()));
// set caching
Cache cache = new Cache();
cache.setNeverCache(false);
cache.setMustRevalidate(true);
cache.setLastModified(modified);
res.setCache(cache);
// get the content and stream directly to the response output stream
// assuming the repository is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
try
{
reader.getContent(res.getOutputStream());
}
catch (SocketException e1)
{
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
}
catch (ContentIOException e2)
{
if (logger.isInfoEnabled())
logger.info("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
}
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
* The content is supplied directly in the reponse. This generally means a browser will
* attempt to open the content directly if possible, else it will prompt to save the file.
*
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name end element to return on the url (used by the browser on Save)
*
* @return URL to download the content from the specified node
*/
public final static String generateNodeURL(NodeRef ref, String name)
{
return MessageFormat.format(NODE_URL, new Object[] {
ref.getStoreRef().getProtocol(),
ref.getStoreRef().getIdentifier(),
ref.getId(),
URLEncoder.encode(name) } );
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.jscript.AlfrescoRhinoScriptDebugger;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.Status;
/**
* Javascript Debugger
*
* @author davidc
*/
public class JavascriptDebugger extends DeclarativeWebScript
{
// dependencies
private AlfrescoRhinoScriptDebugger debugger;
/**
* @param ticketComponent
*/
public void setDebugger(AlfrescoRhinoScriptDebugger debugger)
{
this.debugger = debugger;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
// construct model
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("visible", debugger.isVisible());
return model;
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.jscript.AlfrescoRhinoScriptDebugger;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.Status;
/**
* Javascript Debugger
*
* @author davidc
*/
public class JavascriptDebuggerPost extends DeclarativeWebScript
{
// dependencies
private AlfrescoRhinoScriptDebugger debugger;
/**
* @param ticketComponent
*/
public void setDebugger(AlfrescoRhinoScriptDebugger debugger)
{
this.debugger = debugger;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
String visibleStr = req.getParameter("visible");
boolean visible = Boolean.valueOf(visibleStr);
if (visible)
{
debugger.show();
}
else
{
debugger.hide();
}
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("visible", debugger.isVisible());
return model;
}
}

View File

@@ -0,0 +1,419 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.io.StringWriter;
import java.io.Writer;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.template.TemplateNode;
import org.alfresco.repo.web.scripts.RepositoryImageResolver;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.util.GUID;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.URLEncoder;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.Status;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;
/**
* Alfresco Keyword (simple) Search Service
*
* @author davidc
*/
public class KeywordSearch extends DeclarativeWebScript
{
// Logger
private static final Log logger = LogFactory.getLog(KeywordSearch.class);
// search parameters
// TODO: allow configuration of search store
protected static final StoreRef SEARCH_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
protected static final int DEFAULT_ITEMS_PER_PAGE = 10;
protected static final String QUERY_FORMAT = "query_";
// dependencies
protected ServiceRegistry serviceRegistry;
protected RepositoryImageResolver imageResolver;
protected SearchService searchService;
/**
* @param searchService
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/**
* @param imageResolver
*/
public void setRepositoryImageResolver(RepositoryImageResolver imageResolver)
{
this.imageResolver = imageResolver;
}
/**
* @param serviceRegistry
*/
public void setServiceRegistry(ServiceRegistry serviceRegistry)
{
this.serviceRegistry = serviceRegistry;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
//
// process arguments
//
String searchTerms = req.getParameter("q");
ParameterCheck.mandatoryString("q", searchTerms);
String startPageArg = req.getParameter("p");
int startPage = 1;
try
{
startPage = new Integer(startPageArg);
}
catch(NumberFormatException e)
{
// NOTE: use default startPage
}
String itemsPerPageArg = req.getParameter("c");
int itemsPerPage = DEFAULT_ITEMS_PER_PAGE;
try
{
itemsPerPage = new Integer(itemsPerPageArg);
}
catch(NumberFormatException e)
{
// NOTE: use default itemsPerPage
}
Locale locale = I18NUtil.getLocale();
String language = req.getParameter("l");
if (language != null && language.length() > 0)
{
// NOTE: Simple conversion from XML Language Id to Java Locale Id
locale = new Locale(language.replace("-", "_"));
}
//
// execute the search
//
SearchResult results = search(searchTerms, startPage, itemsPerPage, locale, req);
//
// create model
//
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("search", results);
return model;
}
/**
* Execute the search
*
* @param searchTerms
* @param startPage
* @return
*/
private SearchResult search(String searchTerms, int startPage, int itemsPerPage, Locale locale, WebScriptRequest req)
{
SearchResult searchResult = null;
ResultSet results = null;
try
{
// construct search statement
String[] terms = searchTerms.split(" ");
Map<String, Object> statementModel = new HashMap<String, Object>(7, 1.0f);
statementModel.put("args", createArgs(req));
statementModel.put("terms", terms);
Writer queryWriter = new StringWriter(1024);
renderFormatTemplate(QUERY_FORMAT, statementModel, queryWriter);
String query = queryWriter.toString();
// execute query
if (logger.isDebugEnabled())
{
logger.debug("Search parameters: searchTerms=" + searchTerms + ", startPage=" + startPage + ", itemsPerPage=" + itemsPerPage + ", search locale=" + locale.toString());
logger.debug("Issuing lucene search: " + query);
}
SearchParameters parameters = new SearchParameters();
parameters.addStore(SEARCH_STORE);
parameters.setLanguage(SearchService.LANGUAGE_LUCENE);
parameters.setQuery(query);
if (locale != null)
{
parameters.addLocale(locale);
}
results = searchService.query(parameters);
int totalResults = results.length();
if (logger.isDebugEnabled())
logger.debug("Results: " + totalResults + " rows (limited: " + results.getResultSetMetaData().getLimitedBy() + ")");
// are we out-of-range
int totalPages = (totalResults / itemsPerPage);
totalPages += (totalResults % itemsPerPage != 0) ? 1 : 0;
if (totalPages != 0 && (startPage < 1 || startPage > totalPages))
{
throw new WebScriptException("Start page " + startPage + " is outside boundary of " + totalPages + " pages");
}
// construct search result
searchResult = new SearchResult();
searchResult.setSearchTerms(searchTerms);
searchResult.setLocale(locale);
searchResult.setItemsPerPage(itemsPerPage);
searchResult.setStartPage(startPage);
searchResult.setTotalResults(totalResults);
if (totalResults == 0)
{
searchResult.setTotalPages(0);
searchResult.setStartIndex(0);
searchResult.setTotalPageItems(0);
}
else
{
searchResult.setTotalPages(totalPages);
searchResult.setStartIndex(((startPage -1) * itemsPerPage) + 1);
searchResult.setTotalPageItems(Math.min(itemsPerPage, totalResults - searchResult.getStartIndex() + 1));
}
SearchTemplateNode[] nodes = new SearchTemplateNode[searchResult.getTotalPageItems()];
for (int i = 0; i < searchResult.getTotalPageItems(); i++)
{
NodeRef node = results.getNodeRef(i + searchResult.getStartIndex() - 1);
float score = results.getScore(i + searchResult.getStartIndex() - 1);
nodes[i] = new SearchTemplateNode(node, score);
}
searchResult.setResults(nodes);
return searchResult;
}
finally
{
if (results != null)
{
results.close();
}
}
}
/**
* Search Result
*
* @author davidc
*/
public static class SearchResult
{
private String id;
private String searchTerms;
private Locale locale;
private int itemsPerPage;
private int totalPages;
private int totalResults;
private int totalPageItems;
private int startPage;
private int startIndex;
private SearchTemplateNode[] results;
public int getItemsPerPage()
{
return itemsPerPage;
}
/*package*/ void setItemsPerPage(int itemsPerPage)
{
this.itemsPerPage = itemsPerPage;
}
public TemplateNode[] getResults()
{
return results;
}
/*package*/ void setResults(SearchTemplateNode[] results)
{
this.results = results;
}
public int getStartIndex()
{
return startIndex;
}
/*package*/ void setStartIndex(int startIndex)
{
this.startIndex = startIndex;
}
public int getStartPage()
{
return startPage;
}
/*package*/ void setStartPage(int startPage)
{
this.startPage = startPage;
}
public int getTotalPageItems()
{
return totalPageItems;
}
/*package*/ void setTotalPageItems(int totalPageItems)
{
this.totalPageItems = totalPageItems;
}
public int getTotalPages()
{
return totalPages;
}
/*package*/ void setTotalPages(int totalPages)
{
this.totalPages = totalPages;
}
public int getTotalResults()
{
return totalResults;
}
/*package*/ void setTotalResults(int totalResults)
{
this.totalResults = totalResults;
}
public String getSearchTerms()
{
return searchTerms;
}
/*package*/ void setSearchTerms(String searchTerms)
{
this.searchTerms = searchTerms;
}
public Locale getLocale()
{
return locale;
}
/**
* @return XML 1.0 Language Identification
*/
public String getLocaleId()
{
return locale.toString().replace('_', '-');
}
/*package*/ void setLocale(Locale locale)
{
this.locale = locale;
}
public String getId()
{
if (id == null)
{
id = GUID.generate();
}
return id;
}
}
/**
* Search result row template node
*/
public class SearchTemplateNode extends TemplateNode
{
protected final static String URL = "/api/node/content/{0}/{1}/{2}/{3}";
private static final long serialVersionUID = -1791913270786140012L;
private float score;
/**
* Construct
*
* @param nodeRef
* @param score
*/
public SearchTemplateNode(NodeRef nodeRef, float score)
{
super(nodeRef, serviceRegistry, KeywordSearch.this.imageResolver.getImageResolver());
this.score = score;
}
/**
* Gets the result row score
*
* @return score
*/
public float getScore()
{
return score;
}
/* (non-Javadoc)
* @see org.alfresco.repo.template.BaseContentNode#getUrl()
*/
@Override
public String getUrl()
{
return MessageFormat.format(URL, new Object[] {
getNodeRef().getStoreRef().getProtocol(),
getNodeRef().getStoreRef().getIdentifier(),
getNodeRef().getId(),
URLEncoder.encode(getName()) } );
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.Status;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
/**
* Login and establish a ticket
*
* @author davidc
*/
public class Login extends DeclarativeWebScript
{
// dependencies
private AuthenticationService authenticationService;
/**
* @param authenticationService
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
// extract username and password
String username = req.getParameter("u");
if (username == null || username.length() == 0)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Username not specified");
}
String password = req.getParameter("pw");
if (password == null)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Password not specified");
}
try
{
// get ticket
authenticationService.authenticate(username, password.toCharArray());
// add ticket to model for javascript and template access
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("ticket", authenticationService.getCurrentTicket());
return model;
}
catch(AuthenticationException e)
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Login failed");
}
finally
{
authenticationService.clearCurrentSecurityContext();
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.TicketComponent;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.Status;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
/**
* Login Ticket
*
* @author davidc
*/
public class LoginTicket extends DeclarativeWebScript
{
// dependencies
private TicketComponent ticketComponent;
/**
* @param ticketComponent
*/
public void setTicketComponent(TicketComponent ticketComponent)
{
this.ticketComponent = ticketComponent;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
// retrieve ticket from request and current ticket
String ticket = req.getExtensionPath();
if (ticket == null && ticket.length() == 0)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Ticket not specified");
}
// construct model for ticket
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("ticket", ticket);
try
{
String ticketUser = ticketComponent.validateTicket(ticket);
// do not go any further if tickets are different
if (!AuthenticationUtil.getCurrentUserName().equals(ticketUser))
{
status.setRedirect(true);
status.setCode(HttpServletResponse.SC_NOT_FOUND);
status.setMessage("Ticket not found");
}
}
catch(AuthenticationException e)
{
status.setRedirect(true);
status.setCode(HttpServletResponse.SC_NOT_FOUND);
status.setMessage("Ticket not found");
}
return model;
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.TicketComponent;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.Status;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
/**
* Delete Login Ticket
*
* @author davidc
*/
public class LoginTicketDelete extends DeclarativeWebScript
{
// dependencies
private AuthenticationService authenticationService;
private TicketComponent ticketComponent;
/**
* @param ticketComponent
*/
public void setTicketComponent(TicketComponent ticketComponent)
{
this.ticketComponent = ticketComponent;
}
/**
* @param authenticationService
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
// retrieve ticket from request and current ticket
String ticket = req.getExtensionPath();
if (ticket == null && ticket.length() == 0)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Ticket not specified");
}
// construct model for ticket
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("ticket", ticket);
try
{
String ticketUser = ticketComponent.validateTicket(ticket);
// do not go any further if tickets are different
if (!AuthenticationUtil.getCurrentUserName().equals(ticketUser))
{
status.setCode(HttpServletResponse.SC_NOT_FOUND);
status.setMessage("Ticket not found");
}
else
{
// delete the ticket
authenticationService.invalidateTicket(ticket);
status.setMessage("Deleted Ticket " + ticket);
}
}
catch(AuthenticationException e)
{
status.setCode(HttpServletResponse.SC_NOT_FOUND);
status.setMessage("Ticket not found");
}
status.setRedirect(true);
return model;
}
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigService;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.Status;
import org.alfresco.web.scripts.WebScriptRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* List of (server-side) registered Search Engines
*
* @author davidc
*/
public class SearchEngines extends DeclarativeWebScript
{
// url argument values
public static final String URL_ARG_DESCRIPTION = "description";
public static final String URL_ARG_TEMPLATE = "template";
public static final String URL_ARG_ALL = "all";
// Logger
private static final Log logger = LogFactory.getLog(SearchEngines.class);
// dependencies
protected ConfigService configService;
protected SearchProxy searchProxy;
/**
* @param configService
*/
public void setConfigService(ConfigService configService)
{
this.configService = configService;
}
/**
* @param searchProxy
*/
public void setSearchProxy(SearchProxy searchProxy)
{
this.searchProxy = searchProxy;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@SuppressWarnings("deprecation")
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
String urlType = req.getParameter("type");
if (urlType == null || urlType.length() == 0)
{
urlType = URL_ARG_DESCRIPTION;
}
else if (!urlType.equals(URL_ARG_DESCRIPTION) && !urlType.equals(URL_ARG_TEMPLATE) && !urlType.equals(URL_ARG_ALL))
{
urlType = URL_ARG_DESCRIPTION;
}
//
// retrieve open search engines configuration
//
Set<UrlTemplate> urls = getUrls(urlType);
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("urltype", urlType);
model.put("engines", urls);
return model;
}
/**
* Retrieve registered search engines
*
* @return set of search engines
*/
private Set<UrlTemplate> getUrls(String urlType)
{
if (logger.isDebugEnabled())
logger.debug("Search Engine parameters: urltype=" + urlType);
Set<UrlTemplate> urls = new HashSet<UrlTemplate>();
Config config = configService.getConfig("OpenSearch");
OpenSearchConfigElement searchConfig = (OpenSearchConfigElement)config.getConfigElement(OpenSearchConfigElement.CONFIG_ELEMENT_ID);
for (OpenSearchConfigElement.EngineConfig engineConfig : searchConfig.getEngines())
{
Map<String, String> engineUrls = engineConfig.getUrls();
for (Map.Entry<String, String> engineUrl : engineUrls.entrySet())
{
String type = engineUrl.getKey();
String url = searchProxy.createUrl(engineConfig, type);
if ((urlType.equals(URL_ARG_ALL)) ||
(urlType.equals(URL_ARG_DESCRIPTION) && type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)) ||
(urlType.equals(URL_ARG_TEMPLATE) && !type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)))
{
String label = engineConfig.getLabel();
String labelId = engineConfig.getLabelId();
if (labelId != null && labelId.length() > 0)
{
String i18nLabel = I18NUtil.getMessage(labelId);
if (i18nLabel == null && label == null)
{
label = (i18nLabel == null) ? "$$" + labelId + "$$" : i18nLabel;
}
}
urls.add(new UrlTemplate(label, type, url));
}
// TODO: Extract URL templates from OpenSearch description
else if (urlType.equals(URL_ARG_TEMPLATE) &&
type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION))
{
}
}
}
if (logger.isDebugEnabled())
logger.debug("Retrieved " + urls.size() + " engine registrations");
return urls;
}
/**
* Model object for representing a registered search engine
*/
public static class UrlTemplate
{
private String type;
private String label;
private String url;
private UrlTemplate engine;
public UrlTemplate(String label, String type, String url)
{
this.label = label;
this.type = type;
this.url = url;
this.engine = null;
}
public UrlTemplate(String label, String type, String url, UrlTemplate engine)
{
this(label, type, url);
this.engine = engine;
}
public String getLabel()
{
return label;
}
public String getType()
{
return type;
}
public String getUrl()
{
return url;
}
public String getUrlType()
{
return (type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION) ? "description" : "template");
}
public UrlTemplate getEngine()
{
return engine;
}
}
}

View File

@@ -0,0 +1,317 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.bean;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigService;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement;
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.EngineConfig;
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.ProxyConfig;
import org.alfresco.web.scripts.AbstractWebScript;
import org.alfresco.web.scripts.FormatRegistry;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
import org.alfresco.web.scripts.servlet.HTTPProxy;
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.InitializingBean;
/**
* Alfresco OpenSearch Proxy Service
*
* Provides the ability to submit a request to a registered search engine
* via the Alfresco server.
*
* @author davidc
*/
public class SearchProxy extends AbstractWebScript implements InitializingBean
{
// Logger
private static final Log logger = LogFactory.getLog(SearchProxy.class);
// dependencies
protected FormatRegistry formatRegistry;
protected ConfigService configService;
protected OpenSearchConfigElement searchConfig;
protected String proxyPath;
/**
* @param formatRegistry
*/
public void setFormatRegistry(FormatRegistry formatRegistry)
{
this.formatRegistry = formatRegistry;
}
/**
* @param configService
*/
public void setConfigService(ConfigService configService)
{
this.configService = configService;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception
{
Config config = configService.getConfig("OpenSearch");
searchConfig = (OpenSearchConfigElement)config.getConfigElement(OpenSearchConfigElement.CONFIG_ELEMENT_ID);
if (searchConfig == null)
{
throw new WebScriptException("OpenSearch configuration not found");
}
ProxyConfig proxyConfig = searchConfig.getProxy();
if (proxyConfig == null)
{
throw new WebScriptException("OpenSearch proxy configuration not found");
}
proxyPath = proxyConfig.getUrl();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
public void execute(WebScriptRequest req, WebScriptResponse res)
throws IOException
{
String extensionPath = req.getExtensionPath();
String[] extensionPaths = extensionPath.split("/");
if (extensionPaths.length != 2)
{
throw new WebScriptException("OpenSearch engine has not been specified as /{engine}/{format}");
}
// retrieve search engine configuration
String engine = extensionPaths[0];
EngineConfig engineConfig = searchConfig.getEngine(engine);
if (engineConfig == null)
{
throw new WebScriptException("OpenSearch engine '" + engine + "' does not exist");
}
// retrieve engine url as specified by format
String format = extensionPaths[1];
String mimetype = formatRegistry.getMimeType(null, format);
if (mimetype == null)
{
throw new WebScriptException("Format '" + format + "' does not map to a registered mimetype");
}
Map<String, String> engineUrls = engineConfig.getUrls();
String engineUrl = engineUrls.get(mimetype);
if (engineUrl == null)
{
throw new WebScriptException("Url mimetype '" + mimetype + "' does not exist for engine '" + engine + "'");
}
// replace template url arguments with actual arguments specified on request
int engineUrlArgIdx = engineUrl.indexOf("?");
if (engineUrlArgIdx != -1)
{
engineUrl = engineUrl.substring(0, engineUrlArgIdx);
}
if (req.getQueryString() != null)
{
engineUrl += "?" + req.getQueryString();
}
if (logger.isDebugEnabled())
logger.debug("Mapping engine '" + engine + "' (mimetype '" + mimetype + "') to url '" + engineUrl + "'");
// issue request against search engine
// NOTE: This web script must be executed in a HTTP servlet environment
if (!(res instanceof WebScriptServletResponse))
{
throw new WebScriptException("Search Proxy must be executed in HTTP Servlet environment");
}
HttpServletResponse servletRes = ((WebScriptServletResponse)res).getHttpServletResponse();
SearchEngineHttpProxy proxy = new SearchEngineHttpProxy(req.getServicePath() + "/" + req.getContextPath(), engine, engineUrl, servletRes);
proxy.service();
}
/**
* OpenSearch HTTPProxy
*
* This proxy remaps OpenSearch links (e.g. previous, next) found in search results.
*
* @author davidc
*/
private class SearchEngineHttpProxy extends HTTPProxy
{
private final static String ATOM_NS_URI = "http://www.w3.org/2005/Atom";
private final static String ATOM_NS_PREFIX = "atom";
private final static String ATOM_LINK_XPATH = "atom:link[@rel=\"first\" or @rel=\"last\" or @rel=\"next\" or @rel=\"previous\" or @rel=\"self\" or @rel=\"alternate\"]";
private String engine;
private String rootPath;
/**
* Construct
*
* @param requestUrl
* @param response
* @throws MalformedURLException
*/
public SearchEngineHttpProxy(String rootPath, String engine, String engineUrl, HttpServletResponse response)
throws MalformedURLException
{
super(engineUrl.startsWith("/") ? rootPath + engineUrl : engineUrl, response);
this.engine = engine;
this.rootPath = rootPath;
}
/* (non-Javadoc)
* @see org.alfresco.web.app.servlet.HTTPProxy#writeResponse(java.io.InputStream, java.io.OutputStream)
*/
@Override
protected void writeResponse(InputStream input, OutputStream output)
throws IOException
{
if (response.getContentType().startsWith(MimetypeMap.MIMETYPE_ATOM) ||
response.getContentType().startsWith(MimetypeMap.MIMETYPE_RSS))
{
// Only post-process ATOM and RSS feeds
// Replace all navigation links with "proxied" versions
SAXReader reader = new SAXReader();
try
{
Document document = reader.read(input);
Element rootElement = document.getRootElement();
XPath xpath = rootElement.createXPath(ATOM_LINK_XPATH);
Map<String,String> uris = new HashMap<String,String>();
uris.put(ATOM_NS_PREFIX, ATOM_NS_URI);
xpath.setNamespaceURIs(uris);
List nodes = xpath.selectNodes(rootElement);
Iterator iter = nodes.iterator();
while (iter.hasNext())
{
Element element = (Element)iter.next();
Attribute hrefAttr = element.attribute("href");
String mimetype = element.attributeValue("type");
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MimetypeMap.MIMETYPE_HTML;
}
String url = createUrl(engine, hrefAttr.getValue(), mimetype);
if (url.startsWith("/"))
{
url = rootPath + url;
}
hrefAttr.setValue(url);
}
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(output, outputFormat);
writer.write(rootElement);
writer.flush();
}
catch(DocumentException e)
{
throw new IOException(e.toString());
}
}
else
{
super.writeResponse(input, output);
}
}
}
/**
* Construct a "proxied" search engine url
*
* @param engine engine name (as identified by <engine proxy="<name>">)
* @param mimetype url to proxy (as identified by mimetype)
* @return "proxied" url
*/
public String createUrl(OpenSearchConfigElement.EngineConfig engine, String mimetype)
{
Map<String, String> urls = engine.getUrls();
String url = urls.get(mimetype);
if (url != null)
{
String proxy = engine.getProxy();
if (proxy != null && !mimetype.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION))
{
url = createUrl(proxy, url, mimetype);
}
}
return url;
}
/**
* Construct a "proxied" search engine url
*
* @param engine engine name (as identified by <engine proxy="<name>">)
* @param url engine url
* @param mimetype mimetype of url
* @return "proxied" url
*/
public String createUrl(String engine, String url, String mimetype)
{
String format = formatRegistry.getFormat(null, mimetype);
if (format == null)
{
throw new WebScriptException("Mimetype '" + mimetype + "' is not registered.");
}
String proxyUrl = null;
int argIdx = url.indexOf("?");
if (argIdx == -1)
{
proxyUrl = proxyPath + "/" + engine + "/" + format;
}
else
{
proxyUrl = proxyPath + "/" + engine + "/" + format + url.substring(argIdx);
}
return proxyUrl;
}
}

View File

@@ -0,0 +1,282 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.config;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.config.ConfigElement;
import org.alfresco.config.ConfigException;
import org.alfresco.config.element.ConfigElementAdapter;
/**
* Custom config element that represents the config data for open search
*
* @author davidc
*/
public class OpenSearchConfigElement extends ConfigElementAdapter
{
public static final String CONFIG_ELEMENT_ID = "opensearch";
private ProxyConfig proxy;
private Set<EngineConfig> engines = new HashSet<EngineConfig>(8, 10f);
private Map<String, EngineConfig> enginesByProxy = new HashMap<String, EngineConfig>();
/**
* Default constructor
*/
public OpenSearchConfigElement()
{
super(CONFIG_ELEMENT_ID);
}
/**
* Constructor
*
* @param name Name of the element this config element represents
*/
public OpenSearchConfigElement(String name)
{
super(name);
}
/**
* @see org.alfresco.config.ConfigElement#getChildren()
*/
public List<ConfigElement> getChildren()
{
throw new ConfigException("Reading the open search config via the generic interfaces is not supported");
}
/**
* @see org.alfresco.config.ConfigElement#combine(org.alfresco.config.ConfigElement)
*/
public ConfigElement combine(ConfigElement configElement)
{
OpenSearchConfigElement newElement = (OpenSearchConfigElement) configElement;
OpenSearchConfigElement combinedElement = new OpenSearchConfigElement();
// add all the plugins from this element
for (EngineConfig plugin : this.getEngines())
{
combinedElement.addEngine(plugin);
}
// add all the plugins from the given element
for (EngineConfig plugin : newElement.getEngines())
{
combinedElement.addEngine(plugin);
}
// set the proxy configuration
ProxyConfig proxyConfig = this.getProxy();
if (proxyConfig != null)
{
combinedElement.setProxy(proxyConfig);
}
return combinedElement;
}
/**
* Sets the proxy configuration
*
* @param proxyConfig
*/
/*package*/ void setProxy(ProxyConfig proxyConfig)
{
this.proxy = proxyConfig;
}
/**
* Gets the proxy configuration
*
* @return The proxy configuration
*/
public ProxyConfig getProxy()
{
return this.proxy;
}
/**
* @return Returns a set of the engines
*/
public Set<EngineConfig> getEngines()
{
return this.engines;
}
/**
* @param proxy name of engine proxy
* @return associated engine config (or null, if none registered against proxy)
*/
public EngineConfig getEngine(String proxy)
{
return this.enginesByProxy.get(proxy);
}
/**
* Adds an engine
*
* @param pluginConfig A pre-configured engine config object
*/
/*package*/ void addEngine(EngineConfig engineConfig)
{
this.engines.add(engineConfig);
String proxy = engineConfig.getProxy();
if (proxy != null && proxy.length() > 0)
{
this.enginesByProxy.put(proxy, engineConfig);
}
}
/**
* Inner class representing the configuration of an OpenSearch engine
*
* @author davidc
*/
public static class EngineConfig
{
protected String label;
protected String labelId;
protected String proxy;
protected Map<String, String> urls = new HashMap<String, String>(8, 10f);
/**
* Construct
*
* @param label
* @param labelId
*/
public EngineConfig(String label, String labelId)
{
if ((label == null || label.length() == 0) && (labelId == null || labelId.length() == 0))
{
throw new IllegalArgumentException("'label' or 'label-id' must be specified");
}
this.label = label;
this.labelId = labelId;
}
/**
* Construct
*
* @param label
* @param labelId
* @param proxy
*/
public EngineConfig(String label, String labelId, String proxy)
{
this(label, labelId);
this.proxy = proxy;
}
/**
* @return I18N label id
*/
public String getLabelId()
{
return labelId;
}
/**
* @return label
*/
public String getLabel()
{
return label;
}
/**
* @return proxy
*/
public String getProxy()
{
return proxy;
}
/**
* Gets the urls supported by this engine
*
* @return urls
*/
public Map<String, String> getUrls()
{
return urls;
}
/**
* Adds a url
*
* @param pluginConfig A pre-configured plugin config object
*/
/*package*/ void addUrl(String mimetype, String uri)
{
this.urls.put(mimetype, uri);
}
}
/**
* Inner class representing the configuration of the OpenSearch proxy
*
* @author davidc
*/
public static class ProxyConfig
{
protected String url;
/**
* Construct
*
* @param url
*/
public ProxyConfig(String url)
{
if (url == null || url.length() == 0)
{
throw new IllegalArgumentException("'url' must be specified");
}
this.url = url;
}
/**
* @return url
*/
public String getUrl()
{
return url;
}
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.config;
import java.util.Iterator;
import org.alfresco.config.ConfigElement;
import org.alfresco.config.ConfigException;
import org.alfresco.config.xml.elementreader.ConfigElementReader;
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.EngineConfig;
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.ProxyConfig;
import org.dom4j.Element;
/**
* Custom element reader to parse config for the open search
*
* @author davidc
*/
public class OpenSearchElementReader implements ConfigElementReader
{
public static final String ELEMENT_OPENSEARCH = "opensearch";
public static final String ELEMENT_ENGINES = "engines";
public static final String ELEMENT_ENGINE = "engine";
public static final String ELEMENT_URL = "url";
public static final String ELEMENT_PROXY = "proxy";
public static final String ATTR_TYPE = "type";
public static final String ATTR_LABEL = "label";
public static final String ATTR_LABEL_ID = "label-id";
public static final String ATTR_PROXY = "proxy";
/**
* @see org.alfresco.config.xml.elementreader.ConfigElementReader#parse(org.dom4j.Element)
*/
@SuppressWarnings("unchecked")
public ConfigElement parse(Element element)
{
OpenSearchConfigElement configElement = null;
if (element != null)
{
String elementName = element.getName();
if (elementName.equals(ELEMENT_OPENSEARCH) == false)
{
throw new ConfigException("OpenSearchElementReader can only parse " + ELEMENT_OPENSEARCH
+ "elements, the element passed was '" + elementName + "'");
}
// go through the registered engines
configElement = new OpenSearchConfigElement();
Element pluginsElem = element.element(ELEMENT_ENGINES);
if (pluginsElem != null)
{
Iterator<Element> engines = pluginsElem.elementIterator(ELEMENT_ENGINE);
while(engines.hasNext())
{
// construct engine
Element engineElem = engines.next();
String label = engineElem.attributeValue(ATTR_LABEL);
String labelId = engineElem.attributeValue(ATTR_LABEL_ID);
String proxy = engineElem.attributeValue(ATTR_PROXY);
EngineConfig engineCfg = new EngineConfig(label, labelId, proxy);
// construct urls for engine
Iterator<Element> urlsConfig = engineElem.elementIterator(ELEMENT_URL);
while (urlsConfig.hasNext())
{
Element urlConfig = urlsConfig.next();
String type = urlConfig.attributeValue(ATTR_TYPE);
String url = urlConfig.getTextTrim();
engineCfg.addUrl(type, url);
}
// register engine config
configElement.addEngine(engineCfg);
}
}
// extract proxy configuration
String url = null;
Element proxyElem = element.element(ELEMENT_PROXY);
if (proxyElem != null)
{
Element urlElem = proxyElem.element(ELEMENT_URL);
if (urlElem != null)
{
url = urlElem.getTextTrim();
ProxyConfig proxyCfg = new ProxyConfig(url);
configElement.setProxy(proxyCfg);
}
}
}
return configElement;
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.facebook;
import java.io.IOException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.web.scripts.Authenticator;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.Description.RequiredAuthentication;
import org.alfresco.web.scripts.facebook.FacebookServletRequest;
import org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory;
import org.alfresco.web.scripts.servlet.WebScriptServletRequest;
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Web Script Authenticator that supports Facebook authentication
* mechanism.
*
* Upon success, the request is authenticated as the Facebook User Id.
*
* @author davidc
*/
public class FacebookAuthenticatorFactory implements ServletAuthenticatorFactory
{
// Logger
private static final Log logger = LogFactory.getLog(FacebookAuthenticator.class);
/* (non-Javadoc)
* @see org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory#create(org.alfresco.web.scripts.servlet.WebScriptServletRequest, org.alfresco.web.scripts.servlet.WebScriptServletResponse)
*/
public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res)
{
if (!(req instanceof FacebookServletRequest))
{
throw new WebScriptException("Facebook request is required; instead a " + req.getClass().getName() + " has been provided");
}
return new FacebookAuthenticator((FacebookServletRequest)req, res);
}
/**
* Web Script Authenticator that supports Facebook authentication
* mechanism.
*
* Upon success, the request is authenticated as the Facebook User Id.
*
* @author davidc
*/
public class FacebookAuthenticator implements Authenticator
{
// FBML for Facebook login redirect
private static final String LOGIN_REDIRECT = "<fb:redirect url=\"http://www.facebook.com/login.php?api_key=%s&v=1.0%s\">";
// dependencies
private FacebookServletRequest fbReq;
private WebScriptServletResponse fbRes;
/**
* Construct
*
* @param authenticationService
* @param req
* @param res
*/
public FacebookAuthenticator(FacebookServletRequest req, WebScriptServletResponse res)
{
this.fbReq = req;
this.fbRes = res;
}
/* (non-Javadoc)
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public boolean authenticate(RequiredAuthentication required, boolean isGuest)
{
String sessionKey = fbReq.getSessionKey();
String user = fbReq.getUserId();
if (logger.isDebugEnabled())
{
logger.debug("fb_sig_session_key = '" + sessionKey + "'");
logger.debug("fb_sig_user = '" + user + "'");
}
if ((sessionKey == null || sessionKey.length() == 0) || (user == null || user.length() == 0))
{
// session has not been established, redirect to login
String apiKey = fbReq.getApiKey();
String canvas = (fbReq.isInCanvas()) ? "&canvas" : "";
if (logger.isDebugEnabled())
{
logger.debug("fb_sig_api_key = '" + apiKey + "'");
logger.debug("fb_sig_in_canvas = '" + canvas + "'");
}
try
{
String redirect = String.format(LOGIN_REDIRECT, apiKey, canvas);
if (logger.isDebugEnabled())
logger.debug("Facebook session not established; redirecting via " + redirect);
fbRes.getWriter().write(redirect);
}
catch (IOException e)
{
throw new WebScriptException("Redirect to login failed", e);
}
return false;
}
if (logger.isDebugEnabled())
logger.debug("Facebook session established; authenticating as user " + user);
// session has been established, authenticate as Facebook user id
AuthenticationUtil.setCurrentUser(user);
return true;
}
}
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.portlet;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.scripts.Authenticator;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.Description.RequiredAuthentication;
import org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory;
import org.alfresco.web.scripts.portlet.WebScriptPortletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Portlet authenticator
*
* @author davidc
*/
public class JSR168PortletAuthenticatorFactory implements PortletAuthenticatorFactory
{
// Logger
private static final Log logger = LogFactory.getLog(JSR168PortletAuthenticatorFactory.class);
// dependencies
private AuthenticationService unprotAuthenticationService;
private TransactionService txnService;
/**
* @param authenticationService
*/
public void setUnprotAuthenticationService(AuthenticationService authenticationService)
{
this.unprotAuthenticationService = authenticationService;
}
/**
* @param transactionService
*/
public void setTransactionService(TransactionService transactionService)
{
this.txnService = transactionService;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory#create(javax.portlet.RenderRequest, javax.portlet.RenderResponse)
*/
public Authenticator create(RenderRequest req, RenderResponse res)
{
return new JSR168PortletAuthenticator(req, res);
}
/**
* Portlet authenticator
*
* @author davidc
*/
public class JSR168PortletAuthenticator implements Authenticator
{
// dependencies
private RenderRequest req;
/**
* Construct
*
* @param authenticationService
* @param req
* @param res
*/
public JSR168PortletAuthenticator(RenderRequest req, RenderResponse res)
{
this.req = req;
}
/*(non-Javadoc)
* @see org.alfresco.web.scripts.Authenticator#authenticate(org.alfresco.web.scripts.Description.RequiredAuthentication, boolean)
*/
public boolean authenticate(RequiredAuthentication required, boolean isGuest)
{
// first look for the username key in the session - we add this by hand for some portals
// when the WebScriptPortletRequest is created
String portalUser = (String)req.getPortletSession().getAttribute(WebScriptPortletRequest.ALFPORTLETUSERNAME);
if (portalUser == null)
{
portalUser = req.getRemoteUser();
}
if (logger.isDebugEnabled())
{
logger.debug("JSR-168 Remote user: " + portalUser);
}
if (isGuest || portalUser == null)
{
if (logger.isDebugEnabled())
logger.debug("Authenticating as Guest");
// authenticate as guest
AuthenticationUtil.setCurrentUser(AuthenticationUtil.getGuestUserName());
}
else
{
if (logger.isDebugEnabled())
logger.debug("Authenticating as user " + portalUser);
UserTransaction txn = null;
try
{
txn = txnService.getUserTransaction();
txn.begin();
if (!unprotAuthenticationService.authenticationExists(portalUser))
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "User " + portalUser + " is not a known Alfresco user");
}
AuthenticationUtil.setCurrentUser(portalUser);
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error authenticating user: " + portalUser, err);
}
finally
{
try
{
if (txn != null)
{
txn.rollback();
}
}
catch (Exception tex)
{
// nothing useful we can do with this
}
}
}
return true;
}
}
}

View File

@@ -0,0 +1,214 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.util.Base64;
import org.alfresco.web.scripts.Authenticator;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.Description.RequiredAuthentication;
import org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory;
import org.alfresco.web.scripts.servlet.WebScriptServletRequest;
import org.alfresco.web.scripts.servlet.WebScriptServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* HTTP Basic Authentication
*
* @author davidc
*/
public class BasicHttpAuthenticatorFactory implements ServletAuthenticatorFactory
{
// Logger
private static Log logger = LogFactory.getLog(BasicHttpAuthenticator.class);
// Component dependencies
private AuthenticationService authenticationService;
/**
* @param authenticationService
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory#create(org.alfresco.web.scripts.servlet.WebScriptServletRequest, org.alfresco.web.scripts.servlet.WebScriptServletResponse)
*/
public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res)
{
return new BasicHttpAuthenticator(req, res);
}
/**
* HTTP Basic Authentication
*
* @author davidc
*/
public class BasicHttpAuthenticator implements Authenticator
{
// dependencies
private WebScriptServletRequest servletReq;
private WebScriptServletResponse servletRes;
/**
* Construct
*
* @param authenticationService
* @param req
* @param res
*/
public BasicHttpAuthenticator(WebScriptServletRequest req, WebScriptServletResponse res)
{
this.servletReq = req;
this.servletRes = res;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.Authenticator#authenticate(org.alfresco.web.scripts.Description.RequiredAuthentication, boolean)
*/
public boolean authenticate(RequiredAuthentication required, boolean isGuest)
{
boolean authorized = false;
//
// validate credentials
//
HttpServletRequest req = servletReq.getHttpServletRequest();
HttpServletResponse res = servletRes.getHttpServletResponse();
String authorization = req.getHeader("Authorization");
String ticket = req.getParameter("alf_ticket");
if (logger.isDebugEnabled())
{
logger.debug("HTTP Authorization provided: " + (authorization != null && authorization.length() > 0));
logger.debug("URL ticket provided: " + (ticket != null && ticket.length() > 0));
}
// authenticate as guest, if service allows
if (isGuest && RequiredAuthentication.guest == required)
{
if (logger.isDebugEnabled())
logger.debug("Authenticating as Guest");
authenticationService.authenticateAsGuest();
authorized = true;
}
// authenticate as specified by explicit ticket on url
else if (ticket != null && ticket.length() > 0)
{
try
{
if (logger.isDebugEnabled())
logger.debug("Authenticating (URL argument) ticket " + ticket);
// assume a ticket has been passed
authenticationService.validate(ticket);
authorized = true;
}
catch(AuthenticationException e)
{
// failed authentication
}
}
// authenticate as specified by HTTP Basic Authentication
else if (authorization != null && authorization.length() > 0)
{
try
{
String[] authorizationParts = authorization.split(" ");
if (!authorizationParts[0].equalsIgnoreCase("basic"))
{
throw new WebScriptException("Authorization '" + authorizationParts[0] + "' not supported.");
}
String decodedAuthorisation = new String(Base64.decode(authorizationParts[1]));
String[] parts = decodedAuthorisation.split(":");
if (parts.length == 1)
{
if (logger.isDebugEnabled())
logger.debug("Authenticating (BASIC HTTP) ticket " + parts[0]);
// assume a ticket has been passed
authenticationService.validate(parts[0]);
authorized = true;
}
else
{
if (logger.isDebugEnabled())
logger.debug("Authenticating (BASIC HTTP) user " + parts[0]);
// assume username and password passed
if (parts[0].equals(AuthenticationUtil.getGuestUserName()))
{
if (required == RequiredAuthentication.guest)
{
authenticationService.authenticateAsGuest();
authorized = true;
}
}
else
{
authenticationService.authenticate(parts[0], parts[1].toCharArray());
authorized = true;
}
}
}
catch(AuthenticationException e)
{
// failed authentication
}
}
//
// request credentials if not authorized
//
if (!authorized)
{
if (logger.isDebugEnabled())
logger.debug("Requesting authorization credentials");
res.setStatus(401);
res.setHeader("WWW-Authenticate", "Basic realm=\"Alfresco\"");
}
return authorized;
}
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* 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 2
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.web.scripts.site;
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
import org.alfresco.util.GUID;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Unit test to test site Web Script API
*
* @author Roy Wetherall
*/
public class TestSiteService extends BaseWebScriptTest
{
private static final String URL_SITES = "/api/sites";
public void testCreateSite() throws Exception
{
String shortName = GUID.generate();
// == Create a new site ==
JSONObject site = new JSONObject();
site.put("sitePreset", "myPreset");
site.put("shortName", shortName);
site.put("title", "myTitle");
site.put("description", "myDescription");
site.put("isPublic", true);
MockHttpServletResponse response = postRequest(URL_SITES, 200, site.toString(), "application/json");
JSONObject result = new JSONObject(response.getContentAsString());
assertEquals("myPreset", result.get("sitePreset"));
assertEquals(shortName, result.get("shortName"));
assertEquals("myTitle", result.get("title"));
assertEquals("myDescription", result.get("description"));
assertTrue(result.getBoolean("isPublic"));
// == Create a site with a duplicate shortName ==
response = postRequest(URL_SITES, 500, site.toString(), "application/json");
result = new JSONObject(response.getContentAsString());
}
public void testGetSites() throws Exception
{
// == Test basic GET with no filters ==
MockHttpServletResponse response = getRequest(URL_SITES, 200);
JSONArray result = new JSONArray(response.getContentAsString());
// TODO formalise this test once i can be sure that i know what's already in the site store
// ie: .. i need to clean up after myself in this test
System.out.println(response.getContentAsString());
}
}