36
Best Practices – Extending the Platform Jared and Rich

BP-6 Repository Customization Best Practices

Embed Size (px)

DESCRIPTION

Alfresco’s highly customizable repository can often seem overwhelming. Learn approaches for adding common customizations requests (Extending Javascript API, Content Modeling, Permission Modeling, packaging, etc.) from current and former Alfresco consulting staff. Learn where we often see the most common errors and participate in open Q&A.

Citation preview

Page 1: BP-6 Repository Customization Best Practices

Best Practices – Extending the Platform!

Jared and Rich!

Page 2: BP-6 Repository Customization Best Practices

Pre - Install!

Environment Validation Tool or EVT • Available on Google Code !

• (http://code.google.com/p/alfresco-environment-validation/)!

• Currently targets version 3.3 (though mostly still applicable)!

• Maintained by Support!Zero Day Config Guide or ZDC • Enterprise Only!

• Available in the KB section of support site!

Page 3: BP-6 Repository Customization Best Practices

Donʼt Query if Donʼt Have to Query!

Know you nodes

JavaScript!

!search.findNode()!

Java!

!new NodeRef()!

Page 4: BP-6 Repository Customization Best Practices

There is a cost!

Web Scripts in the Repo? For Shame! • Extra IO!

• To both the DB and the File System!• Lightly used vs High usage!

Page 5: BP-6 Repository Customization Best Practices

Content Models!

Page 6: BP-6 Repository Customization Best Practices

Do you really need a type?

Important questions to ask!• Is it likely to change frequently!• Is it a fixed state!

Page 7: BP-6 Repository Customization Best Practices

But I really need to change that type!?!

Adding is OK Subtraction is Not If you must remove!• Hide it from the users in the client!• Mark Java references deprecated!• NEVER modify the DB directly!

Page 8: BP-6 Repository Customization Best Practices

Donʼt Force It!

• Donʼt force your model to fit the UI!• Sometimes the best approach is a simple custom UI!• The repository has capabilities beyond what Explorer and Share!

Page 9: BP-6 Repository Customization Best Practices

We Enforce the Law!!

There was a bug the allowed you to work incorrectly across models. We’ve fixed the bug. This may result in broken models when upgrading from earlier versions. Take care to thoroughly test your models before upgrading. You may need to not only fix your model, but massage the data, or fix your custom code.!

Page 10: BP-6 Repository Customization Best Practices

Turn It Off!Have you

tried turning it

off…

When Possible Turn off unneeded Services

• File interfaces!•  Indexing (Less important in 4.0)!• Quota Calculations!• Subsystems!

Page 11: BP-6 Repository Customization Best Practices

Youʼre Using Web Services!?!

SOAP just makes me feel dirty • Use Web Scripts over SOAP API • If you must use SOAP ‒ CMIS*!

*Though creating your own SOAP Client won’t be as easy as just using Apache Chemistry

Page 12: BP-6 Repository Customization Best Practices

BFSIT!?! Bulk File System Import Tool!Available on Google Code, not official supported by Alfresco. Maintained by Alfresco Employees.!

Single purpose import:!Read content (metadata and versions supported) from the Filesystem!

http://code.google.com/p/alfresco-bulk-filesystem-import/!

Page 13: BP-6 Repository Customization Best Practices

Test!

Production != Test!

Page 14: BP-6 Repository Customization Best Practices

Know What You are Doing!

Training and Certification!

Engage Consulting or a Partner!

Forums and Blogs!

Wiki!

Attend Devcon!

Page 15: BP-6 Repository Customization Best Practices

Backup!Pre 4.0

Indexes Database Filesystem

4.0

Indexes * Database Filesystem

Page 16: BP-6 Repository Customization Best Practices

Can We Build It!?!

What is possible with Alfresco?!

You tell us.!

Page 17: BP-6 Repository Customization Best Practices

Can We Fix It!?!

Not Always!

Engage SI partner or Alfresco consulting early!

Weigh the costs: Effort to fix vs. Starting over!

Test. Test. Test.!

Page 18: BP-6 Repository Customization Best Practices

Packaging!

AMPs are not the best and lack some features

But….

…They provide process and encapsulation of customizations!

Page 19: BP-6 Repository Customization Best Practices

Outline!

A few things learned Permissions JavaScript API AttributeService

Page 20: BP-6 Repository Customization Best Practices

A few things learned!

Echo --- having a build process that includes deployment early on, is very useful. – Building an AMP file is not as much trouble as it may seem.!– Many folks already have an Ant or Maven build config around that you can use (do not re-invent the wheel)!

Naming Conventions are important. – If you plan on having multiple customizations in a single repository, this will help avoid conflicts!– Enterprise customers who have a mix of internal development teams and partners must think about this from Day 1.!

Page 21: BP-6 Repository Customization Best Practices

Some Ant examples – Package Amp!

<target name="package-amp" depends="mkdirs, package-jar" > <zip destfile="${amp.file}" > <fileset dir="${build.dir}" includes="lib/*.jar" /> <fileset dir="${project.dir}" includes="lib/*.jar" /> <fileset dir="${project.dir}/source" includes="config/**/*.*, jsp/**/*.*, css/**/*.*" /> <fileset dir="${project.dir}/source/config/alfresco/module/${module.id}" includes="*.properties" excludes="log4j.properties" /> </zip> </target>

Page 22: BP-6 Repository Customization Best Practices

Some Ant examples – Update War! <target name="update-war" depends="package-amp"

<echo>Installing AMP into WAR</echo> <java dir="." fork="true" classname= "org.alfresco.repo.module.tool.ModuleManagementTool"> <classpath refid="class.path" /> <arg line="install ${amp.file} ${war.file} -force -nobackup -verbose"/> </java>

<delete dir="${alfresco.dir}/tomcat/webapps/alfresco" /> <delete dir="${alfresco.dir}/tomcat/temp/Alfresco" /> <delete dir="${alfresco.dir}/tomcat/work/Catalina/localhost/alfresco" />

</target>

Page 23: BP-6 Repository Customization Best Practices

Some Ant examples – Start/Stop Alfresco!

<target name="start-alfresco" description="Start the Alfresco Repository"> <exec executable="/bin/sh"> <arg line='-c "${alfresco.dir}/alfresco.sh start"'/> </exec> </target>

<target name="stop-alfresco“ description="Stop the Alfresco Repository">

<exec executable="/bin/sh"> <arg line='-c "${alfresco.dir}/alfresco.sh stop"'/> </exec> </target>

Page 24: BP-6 Repository Customization Best Practices

About The Example!

This example implements a simple customization that allows documents to be tagged as sendable.

Each document has a status and a document ID – The document ID does not have to be the object ID and is guaranteed

to be unique in the repository.!– The valid statuses are staged, effective and retired.!

Users must have ManageSendable Permission to change the sendable status.

Page 25: BP-6 Repository Customization Best Practices

Extending Permissions!

Why Extend Permissions –  Allows Developers to Secure new functionality with ACLs!–  Allows Developers to Expose new combinations of low level

permissions a new role.!Examples of Extended Permissions –  Share!–  Records Management!

Caveats and Gotchas –  If you create new permissions you will have some extra work

around security.!

Page 26: BP-6 Repository Customization Best Practices

Steps!

Create Permissions Model File – The Records Management and Share Permissions files are good examples!– The DTD is another good source of documentation -- http://wiki.alfresco.com/wiki/PermissionModelDTD!

Wire in the bean – Add the permissionModelBootstrap bean!– Wire in any additional permissions using Security Interceptors (if needed)!– Add any needed permissions to the slingshotDocLibCustomResponse bean!

Page 27: BP-6 Repository Customization Best Practices

Permission Model Code Snippet!

<permissions>

<!-- Namespaces used in type references --> ….

<permissionSet type="senddoc:content" expose="all"> <permissionGroup name="ManageSendable" expose="true"

allowFullControl="false"/>

<!-- The low level permission to control setting the owner of a node --> <permission name="_ManageSendable" expose="false" requiresType="false"> <grantedToGroup permissionGroup="ManageSendable" /> <requiredPermission on="node" type="sys:base" name="_ReadProperties" /> </permission>

</permissionSet>

</permissions>

Page 28: BP-6 Repository Customization Best Practices

Security Interceptor Code Snippet!

<bean id="SendableService_security" class="org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor">

<!– Manager Beans Here <property name="objectDefinitionSource"> <value> com.oldschooltechie.sendable.SendableService.makeNodeEffective=

ACL_NODE.1.senddoc:content.ManageSendable com.oldschooltechie.sendable.SendableService.retireNode=

ACL_NODE.1.senddoc:content.ManageSendable com.oldschooltechie.sendable.SendableService.*=

ACL_ALLOW </value> </property> </bean>

Page 29: BP-6 Repository Customization Best Practices

Creating JavaScript APIs!

Why Create JavaScript APIs – Exposes key functionality to JavaScript!– Allows for the encapsulation of the “heavy lifting” functionality!

Some examples of how Custom Javascript APIs are used – Called from Javascript Based webscripts!– Unit testing underlying Java Functionality from JavaScript Scripts that can be run with the Execute Script Action!

Page 30: BP-6 Repository Customization Best Practices

Steps!

Create the Java Class that will provide the API – Extend the org.alfresco.repo.jscript.BaseScopableProcessorExtension class!– All public methods that are not setters and getters will be exposed as JavaScript methods.!– Make sure that you convert NodeRefs into ScriptNodes and visa versa.!– Make sure that arguments passed and returned are Scalars, Scriptables, Arrays or Maps.!

Wire in the bean – Extend the baseJavaScriptExtension bean!– Set the extensionName property!

Page 31: BP-6 Repository Customization Best Practices

Code Snippet!

public class SendableScriptAPI extends BaseScopableProcessorExtension { // Code Omitted

public ScriptNode getNodeRefById(String docId) { NodeRef result = sendableService.getNodeRefById(docId); return new

ScriptNode(result, this.serviceRegistry, getScope()); }

public void makeSendable(ScriptNode nodeRef,String docId) { sendableService.makeSendable(nodeRef.getNodeRef(), docId); }

}

Page 32: BP-6 Repository Customization Best Practices

Bean Definition!

<bean id="SendableScriptAPI" parent="baseJavaScriptExtension" class=

"com.oldschooltechie.sendable.jscript.SendableScriptAPI"> <property name="extensionName"> <value>sendable</value> </property> <property name="sendableService"> <ref bean="SendableService"/> </property> <property name="serviceRegistry"> <ref bean="ServiceRegistry"/> </property> </bean>

Page 33: BP-6 Repository Customization Best Practices

Attribute Service!

What is the Attribute Service – Allows for the storage of arbitrary key value pairs!– Each key can have up to 3 segments.!– The key segments and values are all Serializables (i.e. can be anything).!

Why Use Atrribute Service – There are a number of use cases…..!– Our use case – properties that must have a unique value across nodes.!• Allows making associations between values and nodes via the Database!• Allows for Enforcing Uniqueness of certain Values!

– AttributeService also allowed for retrieving nodes (immediately across all nodes in a cluster) by a property value. (This is less of an issue in swift).!

Page 34: BP-6 Repository Customization Best Practices

Steps For Using the Attribute Server!

Determine how you will plan on using it. – Think about the Key space – use the fact that the key is segmented.!– Think about the core operations!– Wrap it all in a component.!

Page 35: BP-6 Repository Customization Best Practices

Example Code Snippet…!public static final String SENDABLE_ATTR_NAME = "..SENDABLE_ID.."; public static final String SENDABLE_DOC_ID_ATTR_NAME = "..DOC_ID.."; public void storeDocId(String doc_id,NodeRef nodeRef) { if (attributeService.exists(SENDABLE_ATTR_NAME, SENDABLE_DOC_ID_ATTR_NAME,doc_id)) { // Check to see if this node has already been registered if (!attributeService.getAttribute(SENDABLE_ATTR_NAME, SENDABLE_DOC_ID_ATTR_NAME,doc_id).equals(nodeRef)) { throw new SendableRuntimeException("Duplicate entry id:"+doc_id);

} } attributeService.setAttribute(nodeRef,SENDABLE_ATTR_NAME, SENDABLE_DOC_ID_ATTR_NAME,doc_id); }

Page 36: BP-6 Repository Customization Best Practices

Richard McKnight [email protected] @rmknightstar http://www.oldschooltechie.com

Jared Ottley [email protected] @jottley http://jared.ottleys.net

Contact Information!