Merged DEV/GDOCS to HEAD

Google Doc Integration
- The following configuration must be added to your alfresco-global.properties in order to enable the googleeditable repository behaviour:
  googledocs.username=myuser@bob.com
  googledocs.password=pwd123pwd
  googledocs.googleeditable.enabled=true
Google Docs Share Integration
- Enabled via share-config (see share-config-custom.xml.sample for details)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20018 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Mike Hatfield
2010-04-27 17:08:09 +00:00
parent a289049b41
commit cda2cccfd3
19 changed files with 2040 additions and 117 deletions

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.googledocs;
import org.alfresco.service.namespace.QName;
/**
* Google docs model constants
*/
public interface GoogleDocsModel
{
static final String GOOGLE_DOCS_PREFIX = "gd";
static final String GOOGLE_DOCS_MODEL_1_0_URI = "http://www.alfresco.org/model/googledocs/1.0";
static final QName ASPECT_GOOGLEEDITABLE = QName.createQName(GOOGLE_DOCS_MODEL_1_0_URI, "googleEditable");
static final QName ASPECT_GOOGLERESOURCE = QName.createQName(GOOGLE_DOCS_MODEL_1_0_URI, "googleResource");
static final QName PROP_URL = QName.createQName(GOOGLE_DOCS_MODEL_1_0_URI, "url");
static final QName PROP_RESOURCE_ID = QName.createQName(GOOGLE_DOCS_MODEL_1_0_URI, "resourceId");
static final QName PROP_RESOURCE_TYPE = QName.createQName(GOOGLE_DOCS_MODEL_1_0_URI, "resourceType");
}

View File

@@ -0,0 +1,15 @@
/**
*
*/
package org.alfresco.repo.googledocs;
/**
* Google docs permission context
*/
public enum GoogleDocsPermissionContext
{
PRIVATE,
SHARE_READ,
SHARE_WRITE,
SHARE_READWRITE
}

View File

@@ -0,0 +1,43 @@
package org.alfresco.repo.googledocs;
import java.io.InputStream;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Google docs integration service interface
*/
public interface GoogleDocsService
{
/**
* Create a google doc from a given node. The content of the node will be used
* as a basis of the associated google doc. If the node has no content a new, empty google
* doc of the correct type will be created.
*
* The permission context provides information about how google sharing permissions should be
* set on the created google doc.
*
* @param nodeRef node reference
* @param permissionContext permission context
*/
void createGoogleDoc(NodeRef nodeRef, GoogleDocsPermissionContext permissionContext);
/**
* Deletes the google resource associated with the node reference. This could be a folder or
* document.
*
* @param nodeRef node reference
*/
void deleteGoogleResource(NodeRef nodeRef);
/**
* Gets the content as an input stream of google doc associated with the given node. The
* node must have the google resource aspect and the associated resource should not be a
* folder.
*
* @param nodeRef node reference
* @return InputStream the content of the associated google doc
*/
InputStream getGoogleDocContent(NodeRef nodeRef);
}

View File

@@ -0,0 +1,814 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.googledocs;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.ContentData;
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.AccessPermission;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.gdata.client.GoogleService;
import com.google.gdata.client.docs.DocsService;
import com.google.gdata.data.IEntry;
import com.google.gdata.data.MediaContent;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.acl.AclEntry;
import com.google.gdata.data.acl.AclFeed;
import com.google.gdata.data.acl.AclRole;
import com.google.gdata.data.acl.AclScope;
import com.google.gdata.data.docs.DocumentEntry;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.docs.FolderEntry;
import com.google.gdata.data.docs.PresentationEntry;
import com.google.gdata.data.media.MediaSource;
import com.google.gdata.data.media.MediaStreamSource;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ContentType;
import com.google.gdata.util.ServiceException;
/**
*
*/
public class GoogleDocsServiceImpl implements GoogleDocsService, GoogleDocsModel
{
@SuppressWarnings("unused")
private static Log logger = LogFactory.getLog(GoogleDocsServiceImpl.class);
public static final String TYPE_DOCUMENT = "document";
public static final String TYPE_SPREADSHEET = "spreadsheet";
public static final String TYPE_PRESENTATION = "presentation";
public static final String TYPE_PDF = "pdf";
/** Services */
private DocsService googleDocumentService;
private GoogleService spreadsheetsService;
private NodeService nodeService;
private ContentService contentService;
private PersonService personService;
private MimetypeService mimetypeService;
private PermissionService permissionService;
private OwnableService ownableService;
private AuthorityService authorityService;
/** GoogleDoc base feed url */
private String url = "http://docs.google.com/feeds/default/private/full";
/** Authentication credentials */
private boolean initialised = false;
private String username;
private String password;
private Map<String, String> permissionMap;
/**
* @param googleDocumentService google document service
*/
public void setGoogleDocumentService(DocsService googleDocumentService)
{
this.googleDocumentService = googleDocumentService;
}
/**
* @param spreadsheetsService spread sheets service
*/
public void setSpreadsheetsService(GoogleService spreadsheetsService)
{
this.spreadsheetsService = spreadsheetsService;
}
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param contentService content service
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* @param personService person service
*/
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* @param mimetypeService mime type service
*/
public void setMimetypeService(MimetypeService mimetypeService)
{
this.mimetypeService = mimetypeService;
}
/**
* @param permissionService permission service
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/*
* @param ownableService ownable service
*/
public void setOwnableService(OwnableService ownableService)
{
this.ownableService = ownableService;
}
/**
* @param authorityService authority service
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* @param url root googleDoc URL
*/
public void setUrl(String url)
{
this.url = url;
}
/**
* @param username google service user name
*/
public void setUsername(String username)
{
this.username = username;
}
/**
* @param password google service password
*/
public void setPassword(String password)
{
this.password = password;
}
/**
* @param permissionMap permission map
*/
public void setPermissionMap(Map<String, String> permissionMap)
{
this.permissionMap = permissionMap;
}
/**
* Initialise google docs services
*/
public void initialiseGoogleDocsService()
{
if (initialised == false)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Trying to initialise google docs service for user " + username);
}
if (username == null ||username.length() == 0 || password == null)
{
throw new AlfrescoRuntimeException("No Goolge Docs credentials found. Please set the Google Docs authentication configuration.");
}
try
{
googleDocumentService.setUserCredentials(username, password);
spreadsheetsService.setUserCredentials(username, password);
googleDocumentService.setChunkedMediaUpload(-1);
}
catch (AuthenticationException e)
{
throw new AlfrescoRuntimeException("Unable to connect to Google Docs. Please check the Google Docs authentication configuration.", e);
}
initialised = true;
if (logger.isDebugEnabled() == true)
{
logger.debug("Successfully initialised google docs service for user " + username);
}
}
}
/**
* @see org.alfresco.google.docs.GoogleDocsService#upload(org.alfresco.service.cmr.repository.NodeRef)
*/
public void createGoogleDoc(NodeRef nodeRef, GoogleDocsPermissionContext permissionContext)
{
// Check for mandatory parameters
ParameterCheck.mandatory("nodeRef", nodeRef);
// Initialise google doc services
initialiseGoogleDocsService();
// Get property values
String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
// TODO should be checking to make sure this doesn't already have an associated google doc
// Get content reader
String mimetype = null;
InputStream is = null;
ContentReader contentReader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
if (contentReader == null)
{
// Determine the mimetype from the file extension
mimetype = mimetypeService.guessMimetype(name);
}
else
{
// Get the mime type and input stream from the content reader
mimetype = contentReader.getMimetype();
is = contentReader.getContentInputStream();
}
// Get the parent folder id
DocumentListEntry parentFolder = getParentFolder(nodeRef);
// Create the new google document
DocumentListEntry document = createGoogleDocument(name, mimetype, parentFolder, is);
// Set permissions
setGoogleResourcePermissions(nodeRef, document, permissionContext);
// Set the google document details
setResourceDetails(nodeRef, document);
}
/**
* @see org.alfresco.google.docs.GoogleDocsService#deleteGoogleResource(org.alfresco.service.cmr.repository.NodeRef)
*/
public void deleteGoogleResource(NodeRef nodeRef)
{
// Check for mandatory parameters
ParameterCheck.mandatory("nodeRef", nodeRef);
// Initialise google doc services
initialiseGoogleDocsService();
try
{
if (nodeService.hasAspect(nodeRef, ASPECT_GOOGLERESOURCE) == true)
{
// Get the entry
DocumentListEntry entry = getDocumentListEntry(nodeRef);
if (entry == null)
{
throw new AlfrescoRuntimeException("Unable to find google resource to delete for node " + nodeRef.toString());
}
// Delete the entry
entry.delete();
// Remove the aspect from the node
nodeService.removeAspect(nodeRef, ASPECT_GOOGLERESOURCE);
}
}
catch (ServiceException e)
{
throw new AlfrescoRuntimeException("Unable to delete google resource for the node "+ nodeRef.toString());
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to delete google resource for the node "+ nodeRef.toString());
}
}
/**
*
* @param nodeRef
* @param resourceId
* @param permissionContext
*/
private void setGoogleResourcePermissions(NodeRef nodeRef, DocumentListEntry resource, GoogleDocsPermissionContext permissionContext)
{
// Set the owner of the document
String owner = ownableService.getOwner(nodeRef);
setGoogleResourcePermission(resource, AuthorityType.USER, owner, "owner");
if (GoogleDocsPermissionContext.PRIVATE.equals(permissionContext) == false)
{
Set<AccessPermission> accessPermissions = permissionService.getAllSetPermissions(nodeRef);
for (AccessPermission accessPermission : accessPermissions)
{
String authorityName = accessPermission.getAuthority();
AuthorityType authorityType = accessPermission.getAuthorityType();
String permission = accessPermission.getPermission();
if (permissionMap.containsKey(permission) == true)
{
String aclRole = permissionMap.get(permission);
if (GoogleDocsPermissionContext.SHARE_READ.equals(permissionContext) == true &&
("reader".equals(aclRole) == true || "writer".equals(aclRole) == true))
{
// Set the permission to read
setGoogleResourcePermission(resource, authorityType, authorityName, "reader");
}
else if (GoogleDocsPermissionContext.SHARE_WRITE.equals(permissionContext) == true &&
"writer".equals(aclRole) == true)
{
// Set the permission to write
setGoogleResourcePermission(resource, authorityType, authorityName, "writer");
}
else if (GoogleDocsPermissionContext.SHARE_READWRITE.equals(permissionContext) == true &&
("reader".equals(aclRole) == true || "writer".equals(aclRole) == true))
{
// Set the permission to the current acl
setGoogleResourcePermission(resource, authorityType, authorityName, aclRole);
}
}
}
}
}
/**
*
* @param resourceId
* @param authorityType
* @param authorityName
* @param role
*/
private void setGoogleResourcePermission(DocumentListEntry resource, AuthorityType authorityType, String authorityName, String role)
{
if (AuthorityType.USER.equals(authorityType) == true)
{
// Set the user permissions on the resource
String userEMail = getUserEMail(authorityName);
if (userEMail != null && userEMail.length() != 0)
{
setGoogleResourcePermission(resource, userEMail, role);
}
}
else if (AuthorityType.GROUP.equals(authorityType) == true)
{
Set<String> childAuthorities = authorityService.getContainedAuthorities(AuthorityType.USER, authorityName, false);
for (String childAuthority : childAuthorities)
{
setGoogleResourcePermission(resource, AuthorityType.USER, childAuthority, role);
}
}
}
/**
*
* @param userName
* @return
*/
private String getUserEMail(String userName)
{
String email = null;
NodeRef personNodeRef = personService.getPerson(userName);
if (personNodeRef != null)
{
email = (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_EMAIL);
}
return email;
}
/**
*
* @param nodeRef
* @return
*/
private DocumentListEntry getParentFolder(NodeRef nodeRef)
{
DocumentListEntry folder = null;
NodeRef parentNodeRef = nodeService.getPrimaryParent(nodeRef).getParentRef();
if (parentNodeRef != null)
{
if (nodeService.hasAspect(parentNodeRef, ASPECT_GOOGLERESOURCE) == true)
{
String resourceType = (String)nodeService.getProperty(parentNodeRef, PROP_RESOURCE_TYPE);
String resourceId = (String)nodeService.getProperty(parentNodeRef, PROP_RESOURCE_ID);
folder = getDocumentListEntry(resourceType + ":" + resourceId);
}
else
{
DocumentListEntry parentFolder = getParentFolder(parentNodeRef);
String name = (String)nodeService.getProperty(parentNodeRef, ContentModel.PROP_NAME);
folder = createGoogleFolder(name, parentFolder);
setResourceDetails(parentNodeRef, folder);
}
}
return folder;
}
/**
*
* @param nodeRef
* @param folderId
*/
private void setResourceDetails(final NodeRef nodeRef, final DocumentListEntry documentListEntry)
{
AuthenticationUtil.RunAsWork<Object> runAsWork = new AuthenticationUtil.RunAsWork<Object>()
{
public Object doWork() throws Exception
{
// Create a map of the property values
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1);
props.put(GoogleDocsModel.PROP_RESOURCE_ID, documentListEntry.getDocId());
props.put(GoogleDocsModel.PROP_RESOURCE_TYPE, documentListEntry.getType());
props.put(GoogleDocsModel.PROP_URL, documentListEntry.getDocumentLink().getHref());
// Add the google resource aspect
nodeService.addAspect(nodeRef, GoogleDocsModel.ASPECT_GOOGLERESOURCE, props);
return null;
}
};
// Run as admin
AuthenticationUtil.runAs(runAsWork, AuthenticationUtil.getAdminUserName());
}
/**
* @see org.alfresco.google.docs.GoogleDocsService#getGoogleDocContent(org.alfresco.service.cmr.repository.NodeRef)
*/
public InputStream getGoogleDocContent(NodeRef nodeRef)
{
InputStream result = null;
// Check for mandatory parameters
ParameterCheck.mandatory("nodeRef", nodeRef);
// Initialise google doc services
initialiseGoogleDocsService();
try
{
if (nodeService.hasAspect(nodeRef, ASPECT_GOOGLERESOURCE) == true)
{
String downloadUrl = null;
DocumentListEntry document = getDocumentListEntry(nodeRef);
String docType = document.getType();
ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
String fileExtension = mimetypeService.getExtension(contentData.getMimetype());
if (fileExtension.equals("docx"))
{
fileExtension = "doc";
}
if (docType.equals(TYPE_DOCUMENT) || docType.equals(TYPE_PRESENTATION))
{
downloadUrl = ((MediaContent)document.getContent()).getUri() + "&exportFormat=" + fileExtension;
}
else if (docType.equals(TYPE_SPREADSHEET))
{
downloadUrl = ((MediaContent)document.getContent()).getUri() + "&exportFormat=" + fileExtension;
// If exporting to .csv or .tsv, add the gid parameter to specify which sheet to export
if (fileExtension.equals("csv") || fileExtension.equals("tsv"))
{
downloadUrl += "&gid=0"; // gid=0 will download only the first sheet
}
}
else if (docType.equals(TYPE_PDF))
{
MediaContent mc = (MediaContent)document.getContent();
downloadUrl = mc.getUri();
}
else
{
throw new AlfrescoRuntimeException("Unsuported document type: " + docType);
}
// TODO need to verify that download of a spreadsheet works before we delete this historical code ...
// UserToken docsToken = null;
// if (isSpreadSheet)
// {
// docsToken = (UserToken) googleDocumentService.getAuthTokenFactory().getAuthToken();
// UserToken spreadsheetsToken = (UserToken) spreadsheetsService.getAuthTokenFactory().getAuthToken();
// googleDocumentService.setUserToken(spreadsheetsToken.getValue());
//
// }
MediaContent mc = new MediaContent();
mc.setUri(downloadUrl);
MediaSource ms = googleDocumentService.getMedia(mc);
// if (isSpreadSheet)
// {
// googleDocumentService.setUserToken(docsToken.getValue());
// }
result = ms.getInputStream();
}
else
{
// error since we are trying to download a non-google resource
throw new AlfrescoRuntimeException("Can not download google doc content since no corresponsing google resource could be found");
}
}
catch (ServiceException e)
{
throw new AlfrescoRuntimeException("Unable to get google document stream.", e);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to get google document stream.", e);
}
return result;
}
/**
*
* @param docNodeRef
* @return
*/
private DocumentListEntry getDocumentListEntry(NodeRef docNodeRef)
{
String docType = (String)nodeService.getProperty(docNodeRef, PROP_RESOURCE_TYPE);
String docId = (String)nodeService.getProperty(docNodeRef, PROP_RESOURCE_ID);
return getDocumentListEntry(docType + ":" + docId);
}
/**
*
* @param docResourceId
* @return
*/
private DocumentListEntry getDocumentListEntry(String docResourceId)
{
return getEntry(docResourceId, DocumentListEntry.class);
}
/**
*
* @param <E>
* @param resourceId
* @param entryClass
* @return
*/
private <E extends IEntry> E getEntry(String resourceId, Class<E> entryClass)
{
E result = null;
try
{
URL docEntryURL = new URL(url + "/" + resourceId);
result = googleDocumentService.getEntry(docEntryURL, entryClass);
}
catch (ServiceException e)
{
throw new AlfrescoRuntimeException("Unable to get document list entry for resource " + resourceId, e);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to get document list entry for resource " + resourceId, e);
}
return result;
}
/**
*
* @param name
* @param mimetype
* @param parentFolder
* @param is
* @return
*/
private DocumentListEntry createGoogleDocument(String name, String mimetype, DocumentListEntry parentFolder, InputStream is)
{
DocumentListEntry document = null;
try
{
// Create the media content object
MediaContent mediaContent = new MediaContent();
mediaContent.setMimeType(new ContentType(mimetype));
if (is != null)
{
mediaContent.setMediaSource(new MediaStreamSource(is, mimetype));
}
// Parent folder url
String parentFolderUrl = url;
if (parentFolder != null)
{
parentFolderUrl = ((MediaContent)parentFolder.getContent()).getUri();
}
// Create the document entry object
DocumentListEntry docEntry = null;
if (MimetypeMap.MIMETYPE_EXCEL.equals(mimetype) == true)
{
docEntry = new PresentationEntry();
}
else
{
docEntry = new DocumentEntry();
}
docEntry.setContent(mediaContent);
docEntry.setTitle(new PlainTextConstruct(name));
// Upload the document into the parent folder
document = googleDocumentService.insert(
new URL(parentFolderUrl),
docEntry);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to create google document", e);
}
catch (ServiceException e)
{
throw new AlfrescoRuntimeException("Unable to create google document", e);
}
return document;
}
/**
*
* @param docResourceId
* @param mimeType
* @param is
*/
private void updateGoogleDocContent(DocumentListEntry document, String mimeType, InputStream is)
{
try
{
// Update the existing content
googleDocumentService.getRequestFactory().setHeader("If-Match", "*");
document.setMediaSource(new MediaStreamSource(is, mimeType));
document.updateMedia(false);
googleDocumentService.getRequestFactory().setHeader("If-Match", null);
}
catch (ServiceException e)
{
throw new AlfrescoRuntimeException("Unable to update documents content in google docs", e);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to update documents content in google docs", e);
}
}
/**
*
* @param folderName
* @param parentFolderId
* @return
*/
private DocumentListEntry createGoogleFolder(String folderName, DocumentListEntry parentFolder)
{
DocumentListEntry folderEntry = null;
try
{
// Parent folder url
String parentFolderUrl = url;
if (parentFolder != null)
{
parentFolderUrl = ((MediaContent)parentFolder.getContent()).getUri();
}
// Create the folder entry
FolderEntry folder = new FolderEntry();
folder.setTitle(new PlainTextConstruct(folderName));
// Create the folder
folderEntry = googleDocumentService.insert(
new URL(parentFolderUrl),
folder);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to create Google Folder", e);
}
catch (ServiceException e)
{
throw new AlfrescoRuntimeException("Unable to create Google Folder", e);
}
return folderEntry;
}
/**
* Set permissions on a googleDoc resource
*
* @param resourceId
* @param email
* @param role
*/
private void setGoogleResourcePermission(DocumentListEntry resource, String email, String role)
{
ParameterCheck.mandatory("resource", resource);
ParameterCheck.mandatory("email", email);
ParameterCheck.mandatory("role", role);
try
{
AclRole aclRole = new AclRole(role);
AclScope scope = new AclScope(AclScope.Type.USER, email);
// Get the URL
URL aclFeedLinkURL = new URL(resource.getAclFeedLink().getHref());
// See if we have already set this permission or not
AclEntry aclEntry = null;
AclFeed aclFeed = googleDocumentService.getFeed(aclFeedLinkURL, AclFeed.class);
if (aclFeed != null)
{
List<AclEntry> aclEntries = aclFeed.getEntries();
for (AclEntry tempAclEntry : aclEntries)
{
AclScope tempScope = tempAclEntry.getScope();
if (tempScope.equals(scope) == true)
{
// Existing ACL entry found
aclEntry = tempAclEntry;
break;
}
}
}
if (aclEntry == null)
{
aclEntry = new AclEntry();
aclEntry.setRole(aclRole);
aclEntry.setScope(scope);
googleDocumentService.insert(aclFeedLinkURL, aclEntry);
}
// TODO for now we will not 'update' the permissions if they have already been set ....
//
//else
//{
// AclRole currentAclRole = aclEntry.getRole();
// if (currentAclRole.toString().equals(aclRole.toString()) == false)
// {
// aclEntry.setRole(aclRole);
// googleDocumentService.update(new URL(aclEntry.getEditLink().getHref()), aclEntry);
// }
//}
}
catch (ServiceException e)
{
throw new AlfrescoRuntimeException("Unable to set premissions on google document", e);
}
catch (IOException e)
{
throw new AlfrescoRuntimeException("Unable to set premissions on google document", e);
}
}
}

View File

@@ -0,0 +1,278 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.googledocs;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import javax.transaction.UserTransaction;
import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.management.subsystems.ApplicationContextFactory;
import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.site.SiteServiceImpl;
import org.alfresco.service.cmr.coci.CheckOutCheckInService;
import org.alfresco.service.cmr.model.FileFolderService;
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.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.GUID;
import org.alfresco.util.PropertyMap;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import com.google.gdata.util.ServiceException;
public class GoogleDocumentServiceTest extends TestCase implements GoogleDocsModel
{
private NodeService nodeService;
private GoogleDocsService googleDocsService;
private SiteService siteService;
private TransactionService transactionService;
private FileFolderService fileFolderService;
private ContentService contentService;
private CheckOutCheckInService checkOutCheckInService;
private MutableAuthenticationService authenticationService;
private PersonService personService;
private ApplicationContextFactory subsystem;
private static final String USER_ONE = "GoogleDocUserOne";
private static final String USER_TWO = "GoogleDocUserTwo";
private static final String USER_THREE = "GoogleDocUserThree";
private static final String USER_FOUR = "GoogleDocUserFour";
//private static final String EMAIL_DOMAIN = "@alfresco.com";
private NodeRef folder = null;
private NodeRef nodeRefDoc = null;
private NodeRef nodeRefSpread = null;
private NodeRef nodeRefPres = null;
private NodeRef nodeRefPdf = null;
private NodeRef nodeRef2 = null;
private UserTransaction userTransaction = null;
@Override
protected void setUp() throws Exception
{
ApplicationContext appContext = ApplicationContextHelper.getApplicationContext();
nodeService = (NodeService)appContext.getBean("nodeService");
siteService = (SiteService)appContext.getBean("siteService");
transactionService = (TransactionService)appContext.getBean("transactionService");
fileFolderService = (FileFolderService)appContext.getBean("fileFolderService");
contentService = (ContentService)appContext.getBean("contentService");
checkOutCheckInService = (CheckOutCheckInService)appContext.getBean("checkOutCheckInService");
authenticationService = (MutableAuthenticationService)appContext.getBean("authenticationService");
personService = (PersonService)appContext.getBean("personService");
// Start the user transaction
userTransaction = transactionService.getUserTransaction();
userTransaction.begin();
// Get the sub-system and make sure the googleeditable feature is turned on
subsystem = (ApplicationContextFactory)appContext.getBean("googledocs");
if (subsystem.getProperty("googledocs.googleeditable.enabled").equals("false") == true)
{
subsystem.stop();
subsystem.setProperty("googledocs.googleeditable.enabled", "true");
subsystem.start();
}
// Get the google docs service
ConfigurableApplicationContext childContext = (ConfigurableApplicationContext)subsystem.getApplicationContext();
googleDocsService = (GoogleDocsService)childContext.getBean("googleDocsService");
// Create the test users
createUser(USER_ONE, "rwetherall@alfresco.com");
createUser(USER_TWO, "rwetherall@activiti.com");
createUser(USER_THREE, "roy.wetherall@alfresco.com");
createUser(USER_FOUR, "roy.wetherall@activiti.com");
// Authenticate as user one
AuthenticationUtil.setFullyAuthenticatedUser(USER_ONE);
String id = GUID.generate();
// Create a site to use as holder for our test google documents
siteService.createSite("sitePreset", id, "My Title", "My Description", SiteVisibility.PUBLIC);
NodeRef container = siteService.createContainer(id, "testComponent", null, null);
// Add some memberships to the site
siteService.setMembership(id, USER_TWO, SiteServiceImpl.SITE_COLLABORATOR);
siteService.setMembership(id, USER_THREE, SiteServiceImpl.SITE_CONTRIBUTOR);
siteService.setMembership(id, USER_FOUR, SiteServiceImpl.SITE_CONSUMER);
// Create a folder in our site container
folder = fileFolderService.create(container, "myfolder", ContentModel.TYPE_FOLDER).getNodeRef();
// Create test documents
nodeRefDoc = createTestDocument("mydoc.docx", "alfresco/subsystems/googledocs/default/test.docx", MimetypeMap.MIMETYPE_WORD);
nodeRefSpread = createTestDocument("mydoc.xlsx", "alfresco/subsystems/googledocs/default/test.xlsx", MimetypeMap.MIMETYPE_EXCEL);
// Create an empty content node (simulate creation of a new google doc in UI)
nodeRef2 = fileFolderService.create(folder, "mygoogledoc.doc", ContentModel.TYPE_CONTENT).getNodeRef();
nodeService.addAspect(nodeRef2, ASPECT_GOOGLEEDITABLE, null);
}
private NodeRef createTestDocument(String name, String contentPath, String mimetype)
{
NodeRef nodeRef = fileFolderService.create(folder, name, ContentModel.TYPE_CONTENT).getNodeRef();
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
writer.setEncoding("UTF-8");
writer.setMimetype(mimetype);
InputStream is = getClass().getClassLoader().getResourceAsStream(contentPath);
writer.putContent(is);
return nodeRef;
}
private void createUser(String userName, String email)
{
if (authenticationService.authenticationExists(userName) == false)
{
authenticationService.createAuthentication(userName, "PWD".toCharArray());
PropertyMap ppOne = new PropertyMap(4);
ppOne.put(ContentModel.PROP_USERNAME, userName);
ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
ppOne.put(ContentModel.PROP_EMAIL, email);
ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
personService.createPerson(ppOne);
}
}
@Override
protected void tearDown() throws Exception
{
if (userTransaction != null)
{
userTransaction.rollback();
}
}
public void testGoogleDocUploadDownload() throws Exception
{
googleDocsService.createGoogleDoc(nodeRefDoc, GoogleDocsPermissionContext.SHARE_WRITE);
assertTrue(nodeService.hasAspect(nodeRefDoc, ASPECT_GOOGLERESOURCE));
assertNotNull(nodeService.getProperty(nodeRefDoc, PROP_URL));
assertNotNull(nodeService.getProperty(nodeRefDoc, PROP_RESOURCE_ID));
assertNotNull(nodeService.getProperty(nodeRefDoc, PROP_RESOURCE_TYPE));
System.out.println("Google doc URL: " + nodeService.getProperty(nodeRefDoc, PROP_URL));
System.out.println("Google doc type: " + nodeService.getProperty(nodeRefDoc, PROP_RESOURCE_TYPE));
System.out.println("Google doc id: " + nodeService.getProperty(nodeRefDoc, PROP_RESOURCE_ID));
String downloadFile = downloadFile(googleDocsService.getGoogleDocContent(nodeRefDoc), ".doc");
System.out.println("Download file: " + downloadFile);
// googleDocsService.upload(nodeRefSpread, GoogleDocsPermissionContext.SHARE_WRITE);
//
// assertTrue(nodeService.hasAspect(nodeRefSpread, ASPECT_GOOGLERESOURCE));
// assertNotNull(nodeService.getProperty(nodeRefSpread, PROP_URL));
// assertNotNull(nodeService.getProperty(nodeRefSpread, PROP_RESOURCE_ID));
// assertNotNull(nodeService.getProperty(nodeRefSpread, PROP_RESOURCE_TYPE));
//
// System.out.println("Google doc URL: " + nodeService.getProperty(nodeRefSpread, PROP_URL));
// System.out.println("Google doc type: " + nodeService.getProperty(nodeRefSpread, PROP_RESOURCE_TYPE));
// System.out.println("Google doc id: " + nodeService.getProperty(nodeRefSpread, PROP_RESOURCE_ID));
// downloadFile = downloadFile(googleDocsService.download(nodeRefSpread), ".xls");
// System.out.println("Download file: " + downloadFile);
}
public void testCheckOutCheckIn() throws Exception
{
ContentReader contentReader = contentService.getReader(nodeRef2, ContentModel.PROP_CONTENT);
assertNull(contentReader);
// Check out the empty google document
NodeRef workingCopy = checkOutCheckInService.checkout(nodeRef2);
assertTrue(nodeService.hasAspect(workingCopy, ASPECT_GOOGLERESOURCE));
assertNotNull(nodeService.getProperty(workingCopy, PROP_URL));
assertNotNull(nodeService.getProperty(workingCopy, PROP_RESOURCE_ID));
assertNotNull(nodeService.getProperty(workingCopy, PROP_RESOURCE_TYPE));
System.out.println("Google doc URL: " + nodeService.getProperty(workingCopy, PROP_URL));
System.out.println("Google doc type: " + nodeService.getProperty(workingCopy, PROP_RESOURCE_TYPE));
System.out.println("Google doc id: " + nodeService.getProperty(workingCopy, PROP_RESOURCE_ID));
checkOutCheckInService.checkin(workingCopy, null);
assertFalse(nodeService.hasAspect(nodeRefDoc, ASPECT_GOOGLERESOURCE));
contentReader = contentService.getReader(nodeRef2, ContentModel.PROP_CONTENT);
assertNotNull(contentReader);
}
/**
* Utility method to download input stream to a file for inspection
*
* @param inStream
* @param ext
* @return
* @throws IOException
* @throws MalformedURLException
* @throws ServiceException
*/
private String downloadFile(InputStream inStream, String ext) throws IOException, MalformedURLException, ServiceException
{
File file = File.createTempFile("googleDocTest", ext);
String filePath = file.getAbsolutePath();
FileOutputStream outStream = null;
try
{
outStream = new FileOutputStream(filePath);
int c;
while ((c = inStream.read()) != -1)
{
outStream.write(c);
}
}
finally
{
if (inStream != null)
{
inStream.close();
}
if (outStream != null)
{
outStream.flush();
outStream.close();
}
}
return filePath;
}
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.googledocs;
import java.io.InputStream;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.coci.CheckOutCheckInServicePolicies;
import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.BeforeCancelCheckOut;
import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckIn;
import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckOut;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.NodeServicePolicies.OnAddAspectPolicy;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.service.cmr.dictionary.DictionaryService;
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.namespace.QName;
/**
* Behaviour associated with google editable documents
*
*/
public class GoogleEditableAspect implements NodeServicePolicies.OnAddAspectPolicy,
CheckOutCheckInServicePolicies.OnCheckOut,
CheckOutCheckInServicePolicies.OnCheckIn,
CheckOutCheckInServicePolicies.BeforeCancelCheckOut
{
/** Indicates whether behaviour is enabled or not */
boolean enabled = false;
/** Policy component */
private PolicyComponent policyComponent;
/** Google docs service */
private GoogleDocsService googleDocsService;
/** Node service */
private NodeService nodeService;
/** Dictionary service */
private DictionaryService dictionaryService;
/** Content service */
private ContentService contentService;
/**
* @param enabled true if behaviour enabled, false otherwise
*/
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
/**
* @param policyComponent policy component
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* @param googleDocsService google docs service
*/
public void setGoogleDocsService(GoogleDocsService googleDocsService)
{
this.googleDocsService = googleDocsService;
}
/**
* @param nodeService node service
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* @param dictionaryService dictionary service
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* @param contentService content service
*/
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
/**
* Initialise method
*/
public void init()
{
if (enabled == true)
{
// Register behaviour with policy component
policyComponent.bindClassBehaviour(OnAddAspectPolicy.QNAME,
GoogleDocsModel.ASPECT_GOOGLEEDITABLE ,
new JavaBehaviour(this, "onAddAspect", NotificationFrequency.FIRST_EVENT));
policyComponent.bindClassBehaviour(OnCheckOut.QNAME,
GoogleDocsModel.ASPECT_GOOGLEEDITABLE,
new JavaBehaviour(this, "onCheckOut", NotificationFrequency.FIRST_EVENT));
policyComponent.bindClassBehaviour(OnCheckIn.QNAME,
GoogleDocsModel.ASPECT_GOOGLEEDITABLE,
new JavaBehaviour(this, "onCheckIn", NotificationFrequency.FIRST_EVENT));
policyComponent.bindClassBehaviour(BeforeCancelCheckOut.QNAME,
GoogleDocsModel.ASPECT_GOOGLEEDITABLE,
new JavaBehaviour(this, "beforeCancelCheckOut", NotificationFrequency.FIRST_EVENT));
}
}
/**
* @see org.alfresco.repo.node.NodeServicePolicies.OnAddAspectPolicy#onAddAspect(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName)
*/
public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName)
{
if (nodeService.exists(nodeRef) == true)
{
// Can only make cm:content descendant google editable
QName type = nodeService.getType(nodeRef);
if (dictionaryService.isSubClass(type, ContentModel.TYPE_CONTENT) == false)
{
// Prevent aspect from being applied
throw new AlfrescoRuntimeException("The node (" + nodeRef.toString() + ") can not be made google editable, because it is not a sub type of cm:content.");
}
}
}
/**
* @see org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckOut#onCheckOut(org.alfresco.service.cmr.repository.NodeRef)
*/
public void onCheckOut(NodeRef workingCopy)
{
if (nodeService.exists(workingCopy) == true)
{
// Remove the google editable aspect from the working copy
nodeService.removeAspect(workingCopy, GoogleDocsModel.ASPECT_GOOGLEEDITABLE);
// Upload the content of the working copy to google docs
googleDocsService.createGoogleDoc(workingCopy, GoogleDocsPermissionContext.SHARE_WRITE);
}
}
/**
* @see org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckIn#onCheckIn(org.alfresco.service.cmr.repository.NodeRef)
*/
public void onCheckIn(NodeRef nodeRef)
{
if (nodeService.exists(nodeRef) == true &&
nodeService.hasAspect(nodeRef, GoogleDocsModel.ASPECT_GOOGLERESOURCE) == true)
{
// Get input stream for the google doc
InputStream is = googleDocsService.getGoogleDocContent(nodeRef);
if (is == null)
{
throw new AlfrescoRuntimeException("Unable to complete check in, because the working copy content could not be retrieved from google docs.");
}
// Write the google content into the node
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
writer.putContent(is);
// Delete the associated google resource
googleDocsService.deleteGoogleResource(nodeRef);
}
}
/**
* @see org.alfresco.repo.coci.CheckOutCheckInServicePolicies.BeforeCancelCheckOut#beforeCancelCheckOut(org.alfresco.service.cmr.repository.NodeRef)
*/
public void beforeCancelCheckOut(NodeRef workingCopyNodeRef)
{
if (nodeService.exists(workingCopyNodeRef) == true)
{
// Delete the associated google resource
googleDocsService.deleteGoogleResource(workingCopyNodeRef);
}
}
}