Archive for the ‘Uncategorized’ Category

Disabling Auditable Properties from Being Set Automatically

Sunday, May 3rd, 2009

When performing content ingestion, it is often needed to set some system properties that are governed by the Auditable Aspect. These properties are cm:created, cm:creator, cm:modified, cm:modifier. In 3.0 and 3.1, there is no explicit option to turn these off. If this issue affects you, please vote for this JIRA ticket, but in the meantime, here is a way to get around this when you need to disable automatic setting of these properties temporarily.

Note: we are using some trickery here, and doing things that aren’t typically recommended, so please be very careful and test things out in your environment. This worked for me on Alfresco 3.0SP1.

The auditing properties are being set pretty deep inside the infrastructure code (class HibernateNodeDaoServiceImpl). The code checks whether Auditable aspect is applied, and if so, it sets these properties explicitly. One way to disable this is by modifying the code. The way to do it more cleanly is by temporarily changing contentModel.xml. Auditable aspect applied is a mandatory aspect on cm:object, which is parent of cm:content.

Step 1 – Disabling Automatic Setting of Auditable Properties

So my solution is to remove Auditable as a mandatory aspect and to add those properties to cm:object directly. This is the new definition of cm:object.

<type name=”cm:cmobject”>

<title>Object</title>

<parent>sys:base</parent>

<properties>

<property name=”cm:name”>

<title>Name</title>

<type>d:text</type>

<mandatory enforced=”true”>true</mandatory>

<constraints>

<constraint ref=”cm:filename” />

</constraints>

</property>

<!–temporary added properties to go around auditable –>

<property name=”cm:created”>

<title>Created</title>

<type>d:datetime</type>

</property>

<property name=”cm:creator”>

<title>Creator</title>

<type>d:text</type>

</property>

<property name=”cm:modified”>

<title>Modified</title>

<type>d:datetime</type>

</property>

<property name=”cm:modifier”>

<title>Modifier</title>

<type>d:text</type>

</property>

<property name=”cm:accessed”>

<title>Accessed</title>

<type>d:datetime</type>

</property>

</properties>

<!—- Disable Auditable Aspect

<mandatory-aspects>

<aspect>cm:auditable</aspect>

</mandatory-aspects>

–>

</type>

Additionally, for convenience, it’s a good idea to not make these protected, or enforce them as being mandatory, as they are on the original Auditable aspect. As you can see, we commented out cm:auditable as mandatory aspect on this type, which means the code that sets these properties automatically will not get triggered.

Step 2 – Show Properties in the User Interface

The next step is cosmetic – we need to make these properties visible in our UI so it’s easier to test. For that, you will need to edit CONFIGROOT web-client-config-properties.xml. Add the auditable properties to “content” evaluator:

<config evaluator=”node-type” condition=”content”>

<property-sheet>

<show-property name=”creator” />

<show-property name=”created” />

<show-property name=”modifier” />

<show-property name=”modified” />

This will allow you to see these in the UI.

Step 3 – Set Properties, Migrate Content, Perform Bulk Load, etc.

After a server restart, you have now disabled the automatic setting of properties. You can either set them programmatically (and your changes will no longer get intercepted), or manually through the UI.

Edit Auditable properties

Edit Auditable properties

Note: This is an all or nothing operation – you can’t have it automatically set some properties but not others (to do it you’d have to do metadata extraction or some kind of event handler). This is why this is usually a temporary step as you are loading or migrating content.

After you are done with the content load, the next step is re-enable original model to ensure consistency. You also have a bunch of nodes that don’t have Auditable Aspect applied, so we need to reapply it.

Step 4 – Apply Auditable Aspect to Migrated Content

First, you need to revert to the original content model. To apply auditable aspect to many nodes, you typically write a JavaScript script that walks through the nodes and adds Auditable Aspect.

For applying Auditable aspect manually, you’ll have to add some code to CONFIGROOTweb-client-config.xml so it shows u in Add Aspect action.

<config evaluator=”string-compare” condition=”Action Wizards”>


<!– and the has-aspect condition –>

<aspects>
<aspect name=”generalclassifiable”/>

<aspect name=”complianceable”/>

<aspect name=”dublincore”/>

<aspect name=”auditable”/>

<aspect name=”effectivity”/>

<aspect name=”summarizable”/>

<aspect name=”versionable”/>

<aspect name=”templatable”/>

<aspect name=”emailed”/>

<aspect name=”emailserver:aliasable”/>

<aspect name=”taggable”/>

</aspects>

Another possible solution that might preclude this is to have a rule that automatically adds the Auditable aspect as you create nodes, but I haven’t tested that yet.

Step 5 – Restore original state of contentModel.xml and web-client-config-properties.xml

To get everything back to a consistent state, you now have to restore your original contentModel and UI properties. Because all nodes now have auditable aspect applied, as well as the properties that need to exist do in fact exist, Alfresco will now be able to pick it up from there and manage these properties the way it always does.

Great Surf / Share Learning Resource – Ed Loves Java

Friday, December 12th, 2008

I recently discovered a great set of blog posts digging into Surf and Share.  Ed of EdLovesJava Blog has been playing around and doing some interesting things, first playing with the Surf platform, and now moving over to Share.  There are six blog posts on Learning Surf, and two on Share.   A good reading to expand your knowledge of Surf. 

For a more introductory stuff on Surf, see the Surf Platform Category on the Wiki

There is also a webinar I did a few weeks ago – that one runs through a basic technical overview of Surf and some basic extensions.

Occasional Windows Issue

Wednesday, December 3rd, 2008

I use Windows XP for development, and every so often, I had a strange issue.  I would kill Alfresco, try to start it up again, but would get errors consistent with Alfresco still being up (JVM Bind error below).  It’s caused by java trying to bind a port number, but the port already been taken. 

java.net.BindException: Address already in use: JVM_Bind
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:359)
    at java.net.ServerSocket.bind(ServerSocket.java:319)

I double check that all of my java processes are killed, but no cigar.  I even tried redirecting tomcat to another port until next reboot, but then I’d d also have to redirect RMI ports as well.


I finally figured out the problem.  The port references were kept by OpenOffice process soffice.bin.  Killing it resolved the issue. 


Call for Submissions / Feedback on Alfresco SDK

Saturday, November 22nd, 2008

As somebody who spends a lot of time doing work for Alfresco customers, I use the Alfresco SDK all the time. It’s a great resource, though I felt that it can use a bit of loving to improve it and make it more user-friendly and useful. After having some discussions with engineering, I started work on this area, first focused on bringing it up to date. Additionally, we have a number of great additional samples, many posted on the Developer Toolbox , and the other goal of the effort is to incorporate those samples as more official ones as part of the SDK.

In this post, I’ll talk about what I’ve been working on, ask for feedback, and also ask for contributions in improving the SDK. I’ve been working in a separate branch, so the changes are not available yet publically if you try to look for them.

Phase I as outlined below is what I already completed. Next is Phase II, which mostly involves integrating some existing samples. I also outline some other samples I feel will be useful to have, and ask for ideas on other samples to add things that might be useful. The goal is to have a number of samples that are representative of development tasks that you need to perform when working on customer projects.

Most of all, I ask for your feedback, and for any samples you may have that you think will be useful. I know they are out there. We are looking especially for samples that represent common development tasks. Please contact me at jbarmash at alfresco dot com if you have something to contribute.

I recently found a great service for gathering feedback, please add further suggestions there and vote for various improvement proposals.

http://alfresco.uservoice.com/pages/sdk_improvement

Phase I – Already Completed:

Bring SDK Up To Date

  • Added source code for packages introduces in 3.0
  • Added a few missing jars that were preventing running some samples in Eclipse

Improve Eclipse Experience

  • Renamed Sample Projects to organize them better
  • Reordered SDK Embedded jars to be more alphabetical
  • Added project for source files – importing projects into Eclipse will now have source code automatically attached. Before this, every time I’d download a new SDK and import it into Eclipse, I would have to manually attach the corresponding source files to the SDK (i.e. alfresco-repository.jar and alfresco-repository-src.zip). The goal is to make this step automatic.
  • Added a project for shared properties for Java Embedded Projects – can now set just one property file that will affect multiple projects.

Improve SDK Build Infrastructure

  • Integrated identical Build file for all projects
  • Automatically create AMP files based on directory structure convention. Can easily re-point the location of the SDK, to retarget against other SDKs. Creating AMP files is viewed as being hard, but it’s really not the build file I introduced will automatically create it for you as long as you follow a few conventions. I hope to go through it in a separate post, but here is a link to the project so you can start using it right now.
  • Created master build file that allows to build all the SDK projects, including integrate a set of them into alfresco.war for easier testing. This one will not only be helpful for developers, but, once integrated into the alfresco build file, will allow us to identify any future regressions of SDK samples not building.

Improving Existing Samples

  • Reorganized projects to create AMP Files. This one is a big one in my mind – AMP is the standard extension mechanism that we encourage customers to use. Now everybody will have good samples on how they are supposed to be laid out.

Phase II – Adding Existing Samples

This is my next step – re-testing and adding samples we already have. Here they are, along with priorities:

  • MUST - Exposing new Custom root object to FreeMarker
  • Test it for working with both Alfresco repo and Surf / Share.
  • MUST - Exposing new Custom root object to JavaScript
  • Test it for working with both Alfresco repo and Surf / Share.
  • MUST – Standalone Custom Content Model Project, with validation check
  • MUST – WCM SampleFileSystemDeployment
  • MUST – WCM Metadata Extraction Sample from XML
  • MUST – Surf / Share Dashlet Samples
  • SHOULD – JSF Dialog backed by a Web Script
  • SHOULD Custom Condition backed by a JavaScript (with UI).  Possibly simplify first.
  • COULD – Cascading Component Generator & Lucene-backed Drop Down Component Generator (described here: – http://blogs.alfresco.com/wp/jbarmash/2008/08/18/implementing-cascading-dropdowns-for-editing-properties/ ). There are some dependencies in the product for this that makes this a bit harder than a simple extension.

Phase III – Create New Samples

These we don’t have developed yet, and thus view them as secondary, though some of these are very important. Here I am looking for more feedback, as well as prioritization on what to do when we have time. You will notice that these are more repository-focused at this point – Surf / Share-oriented SDK samples is something we will revisit as well, but after this initial project.

  • SHOULD – WCM – XForm Samples (move them from extras directory)
  • SHOULD – WCM – Custom Widget for XForms (supposedly we have something on this)
  • SHOULD – More standalone Web Script examples, including java-backed web scripts. There are many of these in existence, just need to find something representative.
  • SHOULD – Repository – Custom Transformer Sample
  • SHOULD – Repository – Custom Metadata Extraction Sample
  • COULD – Repository – Custom Authentication Component
  • COULD – Custom Behavior for Content Model
  • COULD – Custom Scheduled Job
  • COULD – AMP That Bootstraps some Data into the repository
  • COULD – Dynamic Content Models and AMP that automatically loads them

Call for Contributions

This is where you can help. Any sample on the Phase III list, or whatever other samples you may already have, would be appreciated. Please contact me and tell me what you have that might be able to include (jbarmash at alfresco dot com). Normal code contributions will be followed, and we are happy to give you the credit you deserve of course. Improving the SDK and having a good set of samples to point customers to is something that should benefit the whole community, and let potential new developers to get up to speed more quickly.

And once again, if you have anything you’d like to contribute that may not be good as a sample, you can do that as well – email me or our community manager Nancy Garrity and we’ll post it up to the Developer Toolbox. You never know, she may even give you a t-shirt or a chumby.

Let’s use this link for ongoing discussion and prioritization of effort.

http://alfresco.uservoice.com/pages/sdk_improvement

Thanks!

NY RoadShow

Tuesday, November 18th, 2008

NY Roadshow was last Friday in New York City. It was a morning event, from nine till noon. It was packed house, with about 40 attendees.

Some of the notable things from the event, (apart from my riveting demonstration of Alfresco Share of course), were the case studies:

    Harvard Business Publishing talked about their use of Alfresco. Of particular interest was the fact that they are using Alfresco as an integrated content management application, both the Document Management as well as Web Content Management. It sounds like they also integrated Alfresco with some interesting technologies, such as Synaptica for Taxonomy and Oracle ERP Suite. They built up a custom interface with JBoss SEAM. Their Web Content Management involves three web properties, and numerous micro-sites. Other interesting integrations on the project were Endeca for Search, MarcLogic for XML storage, integration with Ad networks. Because the presentation was more business focused, I’d like to learn more about some of the internals of these integrations.
    Partner Red Hat (JBoss) spoke about how Open Source delivers true value to the consumers, and how portals help deliver that value.
    Our partner RivetLogic spoke about another interesting case studyConnectedWeddings.com.  ConnectedWeddings received a grant from FaceBook fund to build their application on top of a true enterprise platform. They chose Alfresco, and now they using Alfresco in conjunction with JBoss to power their Facebook application. They can author content in Alfresco WCM and publish it to a delivery environment that surfaces content to Facebook, a website, and iPhone client.

I enjoyed the event, especially since it kept at a brisk pace with a lot of content to cover. I did get a sense that more of a deep dive into some of the 3.0 technologies might have been nice though.

One nice thing that came out of it is that I reconnected with my old college suitemate, who came to the event.

SD Dev Practices – Next Gen Runtimes

Wednesday, October 29th, 2008

Here is the presentation.

SD Practices 2008 – Content Oriented Apps Presentation

Tuesday, October 28th, 2008

Here  is my presentation for the Content-Oriented Apps track.

Tech Talk Live Starts TODAY at 17:00 BST/ 16:00 UTC / 12:00pm EDT / 9:00am PDT

Friday, September 19th, 2008

Alfresco Tech Talk Live is a series of regularly scheduled sessions where attendees get to guide the discussion. Alfresco will host the sessions along with a panel of subject matter experts who will be prepared to answer your questions.

Alfresco Tech Talk Live is a series of regularly scheduled sessions where attendees get to guide the discussion. Alfresco will host the sessions along with a panel of subject matter experts who will be prepared to answer your questions.

Today’s topics will include:

  • CMIS Rollout
  • Alfresco Labs 3B Release
  • Much more!

Learn more at: http://wiki.alfresco.com/wiki/live

Join us at: http://alfresco.acrobat.com/live

WCM Best Practices: How Many Web Forms?

Monday, September 15th, 2008

A customer recently asked me how long it would take to convert a site of theirs to be managed by Alfresco. This is something that comes up a lot, so it’s a good opportunity to discuss the issue. I’ll focus here on migrating a site that’s not managed by any CMS into Alfresco (i.e. no migration process), just a static or dynamic pages that need to be now managed by Alfresco.

The salesy answer is as fast as you can import your pages into Alfresco i.e. as quick as few minutes. This is true, in a way – this will allow you to have the site pages inside Alfresco WCM. You can then modify the pages, and deploy the content through Alfresco. However, the goal of any web content management system is to enable nontechnical users make changes on the website, and this won’t quite do. That means that some redesign is usually warranted. Recently I was talking about my colleague, Peter Monks, about making a decision for when a certain page should be converted to a form, and when it doesn’t make sense.

Of course, I am not talking about the obvious if you have 1000 product pages that all look the same, you clearly need forms, and one or more renditions for creating the pages. But, if you have a page that may change a few times a year, or even less frequently, i.e. About Us page, then is it worth to convert it?

Rule Of Thumb

When making this decision, you have to work with the customer and figure out how often certain page or set of pages will likely need to be changed change. Another, secondary, consideration is the technical level of who needs to make the changes to the page. For example, if you have a somewhat technical person who knows HTML reasonably well responsible for a certain page that doesn’t change frequently, then converting it to an XForm is probably an overkill.

Back to non-technical users – if a Web Form is only going to be used for one or two pages (instances of that type) then it’s probably not worth implementing as a Web Form. Another approach you can take is to see whether it’s possible to implement a more generic Web Form that can handle multiple different “types” of pages.

HTML “BLOBs” for Infrequently Changing Pages

Peter also suggested as a best practice what he called “HTML BLOB” Web Form, which should be used for the one-off pages or page fragments. It’s useful in several cases, and as a “safety valve” of sorts. It lets content contributors create those one off pages in a forms based environment, but without too much Web Form development effort. Pages like “About Us”, “Contact Us” etc. are often good examples of “HTML Blob” pages.

The HTML Blob is basically a simple Web Form with a big text field, probably with a title and summary fields, as well as a “related items” repeating element. All of these are optional, except for the content of course (the BLOB). In that text field you can put html, and that gets converted to an html page. You can also have other “catch all” content types, such as “Link”, “Teaser List”, etc. You do need to be aware that you are mixing up content and presentation, but in this case this is probably OK.

Conversion Process

When approaching a site to be converted, you should go through it and analyze all page types to come up with an initial inventory of content types (web forms). Then do a second sweep. This time, focus on combining and reducing the number of web forms to an absolute minimum – the fewer the better. Keep in mind that you can include both static and dynamic XSDs inside other XSDs. This means that you can share some code across multiple XForms, if that makes sense. This is also the time to decide which pages are candidate for the catchall (blob) pages. Once you reduce the total number of forms to a minimal number, then you can start the estimation process for how long it will take you.

Please share your experiences and ideas in the best way to do the migration of a site to Alfresco in comments.

Dynamic Data-Driven Drop Downs for List Properties

Friday, August 8th, 2008

Dynamic Dropdowns

A customer request that comes up often is a need to create a property that is dynamically populated through drop down list. Alfresco has ability to set a pre-set list of drop-downs (i.e. apple, orange) through the LIST constraint, but there is no way to have list change dynamically.

For more on constraints, see this wiki page: http://wiki.alfresco.com/wiki/Constraints. Also, this post assumes some understanding of Component Generators – they are UI components that get dynamically rendered in the Document / Space details Property Sheet. See http://wiki.alfresco.com/wiki/Component_Generator_Framework.The code accompanying this article can be found on Community Developer Toolbox here.

There are several approaches to doing this, the first one is using the existing infrastructure and extend the List Constraints, and the second is to create your own component generator from scratch that generates the drop down the any way you like.
In this post, I’ll talk about reusing the existing list infrastructure. I built a custom constraint that receives a Lucene query and renders the drop down based on results of that query.

This allows you to model a node hierarchy somewhere and point to that hierarchy through the constraint. You can then maintain that hierarchy, adding or deleting nodes, which in turn will modify your drop down appropriately. For example, you can put nodes as a set of subspaces in the data dictionary, or use categories. A potentially useful artifact of this implementation is security filtering – if you choose to secure your nodes, you can have the drop downs render different for different people, based on what they have access to.

Creating SearchBasedListConstraint

The way list drop down works is that the TextFieldGenerator component generator has explicit code to detect the LIST constraint, and renders itself appropriately. It calls getAllowedValues method on the constraint to get the values the drop down should be populated with. I extended this ListConstraint, since if I implement the getAllowedValues to be dynamically, then the drop down should be dynamic.

In my implementation, I chose to separate the generic dynamic list capability from the Lucene specific capability. I have a class called SearchBasedListConstraint that extends ListOfValuesConstraint, and has an abstract method getSearchResult, which returns the list that will be passed on as AllowedValues. Implement this method in a subclass to be backed by anything you want, a file, a database, etc. Another thing i added
here is a reference to ServiceRegistry, so that Alfresco Repository Services could be called, such as SearchService, or NodeService, by subclases. There are a few other methods, which I will discuss in a later post.

public abstract class SearchBasedListConstraint extends ListOfValuesConstraint
{

@Override
public List<String> getAllowedValues()
{
List<String> allowedValues = getSearchResult();
super.setAllowedValues(allowedValues);
return allowedValues;
}

protected abstract List<String> getSearchResult() ;

There is a good forum post that talks a bit about implementing this as well.

http://forums.alfresco.com/en/viewtopic.php?f=4&t=11687

Dynamic DropDowns based on Lucene Searches

As far as an example implementation, I thought that allowing getSearchResult to be backed by a Lucene Query would be useful, since then you can store your data inside Alfresco. It also means that you can have dynamic querying based on content already in Alfresco, another potentially useful feature. So I subclass SearchBasedListconstraint with LuceneSearchBasedListConstraint. I’d like this to be parametrized and set from the content model (this is where the constraints are set), so I expose setQuery public method. Because the SearchService API requires a StoreRef to be passed, i introduce another setter called setStoreRef. I already have a reference to ServiceRegistry from superclass, so I can just start using it.

We are now ready to perform the search, the code currently is hardcoded to return the Name property.

protected List<String> getSearchResult()
{
if (logger.isDebugEnabled())
logger.debug(“Original Query ” + query);

StoreRef storeRef = new StoreRef(strStoreRef);
ResultSet resultSet = getServiceRegistry().getSearchService().query(storeRef, SearchService.LANGUAGE_LUCENE, finalQuery);
NodeService nodeSvc = getServiceRegistry().getNodeService();

List<String> allowedValues = new ArrayList<String>();
for (ResultSetRow row : resultSet)
{
allowedValues.add((String)nodeSvc.getProperty(row.getNodeRef(), ContentModel.PROP_NAME));
}

return allowedValues;
}

That’s all it takes. in the sample, there is some additional code to manage dependencies between dropdowns, which once again I will explain later.

Configuring Constraints

I am using the exampleModel that gets supplied with Alfresco in the extension directory, and added a couple of new fields – country and city. Here is the definition of constraint, note the parameter type query being set.

<constraint name=”my:customConstraint”
type=”org.alfresco.sample.constraints.LuceneSearchBasedListConstraint” >
<parameter name=”query”>
<value> TYPE:”{http://www.alfresco.org/model/content/1.0}content”
</value>
</parameter>
</constraint>

And now introduce this constraint to a property.

<property name=”my:country”>
<title>Country</title>
<type>d:text</type>
<index enabled=”true”>
<atomic>true</atomic>
<stored>false</stored>
<tokenised>false</tokenised>
</index>
<constraints>
<constraint ref=”my:customConstraint” />
</constraints>
</property>

Bootstrapping Alfresco Node Services

Here we have a bit of an issue. The constraints code does not by default get injected through Spring framework, it in fact gets dynamically instantiated through reflection. However, we need to use Alfresco’s foundation services in it, such as NodeService and SearchService, so we need a reference either to them, or to the ServiceRegistry. The solution is to initialize the Constraint from Spring through a use of static internal variables. Then you can use spring to inject ServiceRegistry to the setter, which in turn sets the internal static variable. From then any instances of the class will have access to the static variable.

Here is the code:

private static ServiceRegistry registry;

public ServiceRegistry getServiceRegistry()
{
return registry;
}

public void setServiceRegistry(ServiceRegistry registry)
{
SearchBasedListConstraint.registry = registry;
}

And now we can configure this, so that the Spring configuratoin takes care of setting the static variable.

<bean id=”LuceneSearchBasedListConstraintInitializer”
class=”org.alfresco.sample.constraints.LuceneSearchBasedListConstraint”>

<property name=”serviceRegistry”>
<ref bean=”ServiceRegistry”/>
</property>
</bean>

And the corresponding configuration:

<bean id=”LuceneSearchBasedListConstraintInitializer”
class=”org.alfresco.sample.constraints.LuceneSearchBasedListConstraint”>

<property name=”serviceRegistry”>
<ref bean=”ServiceRegistry”/>
</property>
</bean>

This should do it.

An even more interesting question is how to create dependencies between properties, i.e. so you can choose a country, and then cities of that country get populated automatically. This is part of the sample I provided, but will be explained in a future post.

Update 05/03/2009 – The Source code is now on the new share site (share.alfresco.com), in Developer Toolbox here.

Blogged with the Flock Browser


Alfresco Home | Legal | Privacy | Accessibility | Site Map | RSS  RSS

© 2012 Alfresco Software, Inc. All Rights Reserved.