57
Alfresco Integrations: What We've Learned So Far Jared Ottley Integrations Engineer

Alfresco Integrations - Alfresco Devcon 2012

Embed Size (px)

DESCRIPTION

Overview of Alfresco Integrations Work

Citation preview

Page 1: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Integrations: What We've Learned So Far

Jared OttleyIntegrations Engineer

Page 2: Alfresco Integrations - Alfresco Devcon 2012

Agenda

•State of the Union

•Projects

•Current Status•Jive Toolkit

•Dropbox

•Maven

•Google Docs•What's New

•oAuth Persistance

•Create Content Callback

•Evaluators, Custom Response

•oAuth

•Transaction Rollback Handling

•JMX

Page 3: Alfresco Integrations - Alfresco Devcon 2012

We've Grown

•Started with one Engineer - me!•Added a Project Manager - Peter Monks•Added another Engineer - Will Abson

Page 4: Alfresco Integrations - Alfresco Devcon 2012

Projects

•Google Docs v2 (Cloud, Enterprise, Community)

•Hyperic Plugin (Community)•Kofax (Enterprise)•XAM Connector (Enterprise)•S3 Connector (Cloud, Enterprise)•Salesforce (Cloud)•Jive Toolkit (Enterprise, Community)•Dropbox Connector (Community)

Page 5: Alfresco Integrations - Alfresco Devcon 2012

Projects (Cont.)

•Spring Social Dropbox (Fork)•Spring Social Google Docs•Spring Social AlfrescoContributed

•oAuth1/2 Persistence Service

•PDF Toolkit

•Share Extras

•Maven AMP Plugin

•Java CORS Filter

•Welsh Language Pack

Page 6: Alfresco Integrations - Alfresco Devcon 2012

Projects (Cont.)

•Share Import-Export Python scripts

•Ubuntu 'QuickStart' scripts

•WordPress Alfresco plugins

•Alfresco Community to Cloud Migration Utility

•And More....

Page 7: Alfresco Integrations - Alfresco Devcon 2012

What does the future hold?

The Future is Fluid

Page 8: Alfresco Integrations - Alfresco Devcon 2012

Jive Toolkit

What is it?A set of pre-built components that allows Jive to store documents in Alfresco while still offering all of the same social features as “native” Jive documents (commenting, rating, discussions, etc.)

Availability?Released Early 2012Current supported release version 1.0.5 for Alfresco 3.4.11

Support PortalCurrent community release version 1.1 for Alfresco 4.1

http://code.google.com/p/alfresco-jive-toolkit/

Page 9: Alfresco Integrations - Alfresco Devcon 2012

Jive Toolkit (Cont.)

Future?•The community project is looking for help.•SolutionSet is taking ownership of the project.•Looking for

o Developerso Testerso Users!o Documentation

Page 10: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Dropbox Connector

What is it?The Alfresco Dropbox Connector allows a user to sync content/folders to their Dropbox Account. Content can be synced to multiple users accounts. When the content is updated in Alfresco it will be synced across all synced Dropbox Accounts. It supports manual updates back to Alfresco from Dropbox.

Availability?It is current available from Google Code (http://code.google.com/p/alfresco-dropbox-integration/). It is available as a community supported project. It requires at least Alfresco 4.1 (Enterprise) or 4.2 (Community)

Page 11: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Dropbox Connector (Cont.)

Status?We are looking for Contributors, Testers, Documentation, Users.

What happened?Sync. Automatic sync between multiple sources is a complicated issue. It is even more complicated when one of the sources doesn't have a full understanding of content lifecycle....or managing it.

Page 12: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Dropbox Connector (Cont.)

Issue 1: One to Many

Content in Alfresco is shared across multiple users but maintains a single source of truth.

When synced to Dropbox .... we have many sources.

Sharing content is explicit: a user has to initiate it. No API support.

Page 13: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Dropbox Connector (Cont.)

Issue 2: Versioning

Dropbox has poor version support.•Revision created with each save•Revisions only available for the past 30 days•Revisions number are non sequential alphanumeric sequences•Modification dates can't be trusted

One to Many + Versioning = Nightmare.

Page 14: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Dropbox Connector (Cont.)

Issue 3: File Changes (1)

Dropbox provides a delta api."A way of letting you keep up with changes to files and folders in a user's Dropbox. You can periodically call /delta to get a list of "delta entries", which are instructions on how to update your local state to match the server's state."

In reality, an entry in the delta list means the files is:...New...Update...Move...Copied...Renamed...an entry with no file metadata means the file has been

...Deleted...Moved...Renamed...

Page 15: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Dropbox Connector (Cont.)

Issue 3: File Changes (2)

It is polling...

...which is expensive...

...which drains already costly resources...

Page 16: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Dropbox Connector (Cont.)

Page 17: Alfresco Integrations - Alfresco Devcon 2012

Alfresco Dropbox Connector (Cont.)

Are we without options?No.

Our proposed approachOut of process polling

CMIS Client to AlfrescoRESTful client of DropboxComplicated ordering of content changes out of process

Page 18: Alfresco Integrations - Alfresco Devcon 2012

Maven

3.0.4 or 3.0.5-SNAPSHOT

Add to pom or settings.xml:

<pluginRepositories> <pluginRepository> <id>alfresco-public</id> <name>Alfresco</name> <url>https://artifacts.alfresco.com/nexus/content/repositories/releases</url> </pluginRepository> <pluginRepository> <id>alfresco-public-snapshots</id> <name>Alfresco</name> <url>https://artifacts.alfresco.com/nexus/content/groups/public-snapshots/</url> </pluginRepository> </pluginRepositories>

Page 19: Alfresco Integrations - Alfresco Devcon 2012

Maven

Alfresco dependencies can be found at

https://artifacts.alfresco.com

Add the amp packaging decleration to your pom.xml

<packaging>amp</packaging>

Page 20: Alfresco Integrations - Alfresco Devcon 2012

Maven

Repo/Share Pom

<plugin> <groupId>org.alfresco.maven.plugin</groupId> <artifactId>maven-amp-plugin</artifactId> <version>3.0.4</version> <extensions>true</extensions> <configuration> <mAmpJarExcludes>alfresco/module/**,alfresco/extension/**,alfresco/messages/**</mAmpJarExcludes> <!--exclude in share --> <archive> <addMavenDescriptor>false</addMavenDescriptor> </archive> </configuration> </plugin>

Page 21: Alfresco Integrations - Alfresco Devcon 2012

Maven

Share Pom (YUI Minification)

<plugin> <groupId>net.alchim31.maven</groupId> <artifactId>yuicompressor-maven-plugin</artifactId> <version>1.2</version> <executions><execution> <id>compressyui</id> <phase>process-resources</phase> <goals><goal>compress</goal></goals> </execution></executions> <configuration> <excludes> <exclude>**/*.css</exclude> <exclude>**/*.get.js</exclude> </excludes> </configuration></plugin>

Page 22: Alfresco Integrations - Alfresco Devcon 2012

Maven

├── module.properties├── pom.xml└── src

├── main│ ├── java│ │ └── org│ │ └── alfresco│ ├── resources│ │ └── alfresco│ │ ├── extension│ │ ├── messages│ │ └── module│ └── webapp│ └── WEB-INF│ └── web.xml└── test

├── java └── resources

Page 23: Alfresco Integrations - Alfresco Devcon 2012

Maven

Build command

mvn clean package [-DskipTests]

Amp location

in target directory

Validate amp content in directory of same name as amp (minus amp extension)

Page 24: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

• Complete rewriteo Usabilityo Functionality

• No Shared Accounto Create and Edit content in their account

• Google is used as an editor, not persistance• Add-on not part of core• Cloud, Enterprise, Community

[Talk about Drive here :-)]

Page 25: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Demo

Page 26: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Page 27: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

OAuth Credentials Store

Provide Token Persistence for oAuth1 and oAuth2Leverages Remote Credentials ServiceDropbox Integrations and Google Docs V2 this service

Page 28: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

How To

private static OAuth2CredentialsStoreService oauth2CredentialsStoreService;

//Store Credentials. RemoteSystemId should be Uniqueoauth2CredentialsStoreService.storePersonalOAuth2Credentials(RemoteSystemId, AccessToken, RefreshToken, ExpiresAt, IssuedAt);

//Retrieve Credentials by RemoteSystemIdOAuth2CredentialsInfo oAuth2CredentialsInfo = oauth2CredentialsStoreService.getPersonalOAuth2Credentials(RemoteSystemId);

//Update Credentials the same way you add new ones...make sure the RemoteSystemId is the sameoauth2CredentialsStoreService.storePersonalOAuth2Credentials(RemoteSystemId, UpdatedAccessToken, UpdatedRefreshToken, UpdatedExpiresAt, UpdatedIssuedAt);

Page 29: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

//Store Shared Credentials. Recomendation: Unqiue RemoteSystemIdoauth2CredentialsStoreService.storeSharedOAuth2Credentials(RemoteSystemId, AccessToken, RefreshToken, ExpiresAt, IssuedAt);

//Retrieve by RemoteSystemId Note: this returns a listList<OAuth2CredentialsInfo> sharedCredentials = oauth2CredentialsStoreService.listSharedOAuth2Credentials(RemoteSystemId);

//Update Share Credentials. Note the specifics method for updating shared credentialsoauth2CredentialsStoreService.updateSharedOAuth2Credentials(oAuth2CredentialsInfo, RemoteSystemId, UpdatedAccessToken, UpdatedRefreshToken, UpdatedExpiresAt, UpdatedIssuedAt);

Page 30: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

//Delete Personal Credentials by RemoteSystemIdoauth2CredentialsStoreService.deletePersonalOAuth2Credentials(RemoteSystemId);

//Delete Share Credentials requires RemoteSystemId and the oAuth2CredentialsInfo instance of the specific credentialsList<OAuth2CredentialsInfo> sharedCredentials = oauth2CredentialsStoreService.listSharedOAuth2Credentials(RemoteSystemId); //find the ones you need in the list oauth2CredentialsStoreService.deleteSharedOAuth2Credentials(RemoteSystemId, oAuth2CredentialsInfo);

Page 31: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Create Content Action

Add to your share-config-custom.xml

<config evaluator="string-compare" condition="DocumentLibrary"> <create-content> <content id="google-docs" label="create-content.googledocs.document" icon="document" index="50" type="javascript"> <param name="function">onGoogledocsActionCreateDocument</param> </content> </create-content></config>

Page 32: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

It supports 3 different actions: link, pagelink or javascript:

* "link" - accepts a "href" param that will be passed a nodeRef token for substitution, used for external links

* "pagelink" - accepts a "page" param that will be passed a nodeRef token for substitution, used for Share links

* "javascript" - accepts & "function" param of an action that will get the current folder item as first argument.

Evaluators are not currently supported, but permission checks are.

Page 33: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

(function() {YAHOO.Bubbling.fire("registerAction", { actionName : "onGoogledocsActionCreateDocument", fn: function dlA_onGoogledocsActionCreateDocument(record) { //Do Work HerecreateGoogleDoc.call(this, record, "document"); }})})();

Page 34: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

DocLib Actions: Evaluators, Custom ResponsesTwo actions:

Edit ContentResume Editing Content

Edit ContentOnly a specific set of content can be edited by Google DocsContent that is currently being edited can't be "edited"User must have write access to the nodeDocument Size LimitsGoogle Docs Service can be turned off

Page 35: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Editing Action

<action id="google-docs-edit-action-link" type="javascript" icon="google-edit" label="googledocs.actions.edit"> <param name="function">onGoogledocsActionEdit</param> </action>

JavaScript or PageLink?

Debugging

http://localhost:8080/alfresco/service/slingshot/doclib2/node/workspace/SpacesStore/8759ce08-acaa-4d69-807e-23c98a53fd17

Page 36: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

User must have write access to the node

<permissions> <permission allow="true">Write</permission> </permissions>

Possible Permissions

CancelCheckOut ChangePermissions CreateChildren Delete Write

Page 37: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Content that is currently being edited can't be "edited"

Content being edited has the gd2:editingInGoogle aspect applied

<bean id="evaluator.doclib.google.docs.doesnothaveaspect" parent="evaluator.doclib.metadata.doesNotHaveAspect"> <property name="aspects"> <list> <value>gd2:editingInGoogle</value> </list> </property>

<property name="negateOutput" value="true" /> </bean>

Page 38: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Document Size Limits

Google Docs has a complex set of sizes (http://support.google.com/drive/bin/answer.py?hl=en&answer=37603)

<bean id="evaluator.doclib.metadata.sizeLimit" class="org.alfresco.integrations.web.evaluator.SizeLimitEvaluator"> <property name="maxDocumentSize" value="2097152"/> <property name="maxSpreadsheetSize" value="20971520"/> <property name="maxPresentationSize" value="52428800"/> </bean>

Page 39: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Remember!

Numeric values in json are doubles.

long size = ((Double)node.get("size")).longValue();String contentType = getContentType(node.get("mimetype").toString());

if (contentType == null || size > getMaxFileSize(contentType)){ return false;}

Page 40: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Only a specific set of content can be edited by Google Docs

application/vnd.openxmlformats-officedocument.presentationml.presentationapplication/vnd.ms-powerpointtext/tab-separated-valuesapplication/vnd.sun.xml.writerapplication/vnd.ms-excelapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetapplication/rtfapplication/mswordapplication/vnd.oasis.opendocument.texttext/plaintext/csvapplication/x-vnd.oasis.opendocument.spreadsheetapplication/vnd.oasis.opendocument.spreadsheet <!-- GOOGLEDOCS-71 -->application/vnd.openxmlformats-officedocument.wordprocessingml.document

Page 41: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

<property name="importFormats"> <map> <entrykey="application/vnd.openxmlformats-officedocument.presentationml.presentation"> <value>presentation</value> </entry>....

</map></property

Page 42: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

<property name="exportFormats"> <map> <entry key="document"> <map> <entry key="application/vnd.openxmlformats-officedocument.wordprocessingml.document"> <value>docx</value> </entry>

...</map></entry>

</map></property>

Page 43: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Bonus

application/x-msmetafile

Page 44: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

<bean id="evaluator.doclib.metadata.isMimetype" class="org.alfresco.integrations.web.evaluator.IsMimetypeEvaluator"/>

<bean id="evaluator.doclib.google.docs.mimetype" parent="evaluator.doclib.metadata.isMimetype"> <property name="mimetypes" value="custom.googledocs.importFormats"/> </bean>

Page 45: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Google Docs Service can be turned off

googledocs.enabled=true

public Serializable populate(){

Map<String, Serializable> map = new LinkedHashMap<String, Serializable>(2); map.put("enabled", (Serializable)googledocsService.isEnabled()); map.put("importFormats", (Serializable)googledocsService.getImportFormats());

return (Serializable)map;}

Page 46: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

<bean id="evaluator.doclib.google.docs.enabled" parent="evaluator.doclib.action.metadataValue"> <property name="accessor" value="custom.googledocs.enabled"/> <property name="comparator"> <bean class="org.alfresco.web.evaluator.StringEqualsComparator"> <property name="value" value="true" /> </bean> </property>

Page 47: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Chaining our Evaluators

Edit Evaluator <bean id="evaluator.doclib.google.docs.edit" parent="evaluator.doclib.action.chainedMatchAll"> <property name="evaluators"> <list> <ref bean="evaluator.doclib.google.docs.enabled"/> <ref bean="evaluator.doclib.google.docs.mimetype" /> <ref bean="evaluator.doclib.google.docs.doesnothaveaspect" /> <ref bean="evaluator.doclib.google.docs.maxsize" /> </list> </property> </bean>

Page 48: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

<bean id="evaluator.doclib.google.docs.resume" parent="evaluator.doclib.action.chainedMatchAll"> <property name="evaluators"> <list> <ref bean="evaluator.doclib.google.docs.aspect"/> <ref bean="evaluator.doclib.indicator.lockOwner"/> </list> </property> </bean>

Resume Edit Evaluator

Page 49: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

OAuth WorkflowAuthentication is a challenge no matter what the authentication type.

oAuth is only part of the solution for Google Docs...but we leverage it to solve other issues as well

We leveraged our own spring-social-google-docs.spring-social-google was not compatiblespring-social-google-docs is a wrapper for gdataNewer google client did not provide a client api for Google Docs

Page 50: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Page 51: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

ComponentsTwo Web Scripts

1. Provides the Authentication URL2. Completes the Authentication

-Persists the Tokens

Client Side JSInitiate the Flow

Calls to RepoOpens ModalDialog or new Window

Secret Sauce: Callback page, browser redirect the auth token to repo

Page 52: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Rollback Callback

Used to handle additional clean up work when a transaction is rolled back. Could be used to perform work in another system or in Alfresco.

Clean up NotificationsSome Unit of Work

Page 53: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

catch (SomeException e) { AlfrescoTransactionSupport.bindListener(new TransactionListenerAdapter() { public void afterRollback() { transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>() { public Object execute() throws Throwable {

//do work here }

}, false, true); } }); //Something maybe needed here like throw new SomeOtherException(e.getMessage(), e); }

Page 54: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

JMX

Any properties you add to for your custom beans to pick up are made read-only in JMX. If you want read write, make a subsystem.

Define your ChildApplicationContextFactory bean in your AMPs module.properties file.

Create a directory structure in your resource directoryalfresco.subsystems.<category>[.<instance>]

Add your systems <name>-context.xml and <name>.properties files

Page 55: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

<bean id="googledocs_v2" class="org.alfresco.repo.management.subsystems.ChildApplicationContextFactory" parent="abstractPropertyBackedBean"> <property name="category"> <value>googledocs</value> </property> <property name="typeName"> <value>v2</value> </property> <property name="instancePath"> <value>v2</value> </property> <property name="autoStart"> <value>true</value> </property> </bean>

Page 56: Alfresco Integrations - Alfresco Devcon 2012

Google Docs V2

Best PracticesKeep your model in you subsystem. Web Scripts Cannot be defined in your subsystemTest what happens when you unload your subsystem

--Subsystems can be automatically reloaded--If you don't want that to happen,

Add programmatic controls to keep its beans from being called

Page 57: Alfresco Integrations - Alfresco Devcon 2012