AccessDeniedException Due to Creating of Thumbnails in Alfresco Share

This week i was in struggle with a realy strange issue in Alfresco. If you belong to a site with lower permissions on this site or something similary you got an exception on Thumnbail-creation. For sure, you can upload and edit a document being added to a site but the creation of the previewes like the images in the doclib as well as the whole webpreview failed if you have no permissions doing a appropriate operation on the particular document you have actually under edit. Thus, its getting weird if you got to a document-details page and its gettin showed up the old content of the old version of the document. So a normal user expects a failure of himself so he is giving himself another try to upload a new version and runs into the same pitfall as the time before … Actually there exists a JIRA-Bug-entry at Alfresco but its still keeped under the open issues so we have to move on with our own ifx regarding this:

So the easiest solution without cross-cutting concers is to using Aspect-orientied programming. With that technique we getting rid of the current AuthenticationContext (the current logged on user) so we can run the thumnailcreation with admin-permissions. This has no drawbacks about permissions.

At first we have to create the appropriated Proxy-Helper class to register a AOP-Class. But be aware its just a little excerpt where you can starting from:

public class PostBeanServiceProcessor implements BeanFactoryPostProcessor { ...

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   for (String bean : affectedBeans) {
      BeanDefinition beanDefinition = beanFactory.getBeanDefinition(bean);
      List<RuntimeBeanNameReference> proxies = (List<RuntimeBeanNameReference>) beanDefinition
      .getPropertyValues().getPropertyValue("interceptorNames").getValue();

      proxies.add(new RuntimeBeanNameReference(this.interceptorName));

      ((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(bean, beanDefinition);
    }
}
...
}

There we go: next step is to add the particular code we want to run on it at a particular timepoint. On our implementation means this that we want to use that code if a thumbnail shall be created or at least updated to a upper version. Then we run this creation with Admin-Functionality.

public class ProxyAdminThumbnailService implements MethodInterceptor{...

public Object invoke(final MethodInvocation method) throws Throwable {
    if( method.getMethod().getName().equals("createThumbnail") ||
       method.getMethod().getName().equals("updateThumbnail")){

       return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() {

          public Object doWork() throws Exception {
            try {
             return method.proceed();
            }
            catch (Throwable e) {
                throw new RuntimeException(e);
            }
          }
       }, AuthenticationUtil.SYSTEM_USER_NAME);
}

return method.proceed();
...
}

This is all we have to do right here: last step is to add the beandefinition for this two classes:

<bean id="mcgThumbnailInterceptor" class="com.westernacher.wps.alfresco.aop.ProxyAdminThumbnailService">
</bean>
<bean id="mcgThumbnailInterception" class="com.westernacher.wps.alfresco.aop.PostBeanServiceProcessor">
   <property name="interceptorName" value="mcgThumbnailInterceptor"/>
   <property name="affectedBeans">
      <list>
        <value>ThumbnailService</value>
      </list>
   </property>
</bean>

Gotcha! Next issue!

A jBPM-Timer Is Not A jBPM-Timer In Relation To Alfresco

Today i was wondering about an unexpected behaviour in jBPM 3.2.2. Im accustomed to add a business time directly on workflowstart so i can set my variables in the processdefinition in the right manner. For instance:

<timer duedate="#{myDueDate}">
   <action>...</action>
</timer>

And this was my AlfrescoCode:

workflowParameters.put("dueDate", "10 business days");
workflowService.startWorkflow(def.id, workflowParameters);

So it doesnt work at all using the Alfresco-Integration of jBPM. I thought im so stupid to forget all the bunch of jBPM-Peaces that i´ve compelled to fillin my head but this wasnt the point as i can see it by now after i wented home and reviewing the codings.

As Alfresco overrides and extends the CreateTimerAction of jBPM we dont calling it anymore “extening” rather than decreasing the amount of possibilities we can take from that Timer as the functionality were partly removed from the base-class (CreateTimerClass). This means in brief, that we can not using such a duration-format like ive mentioned above (10 business hours) as following lines occures at the point of concern where the Baseclass was able to fullfill this cool feature:

if (dueDateExpression.startsWith("#{")) { 
   Object result = JbpmExpressionEvaluator.evaluate(dueDateExpression, executionContext);
   if (!(result instanceof Date)) {
     throw new WorkflowException("duedate expression must evaluate to a date");
}
...

Here we going. We have to pass a ready to start date and you have to calulate out your relativly value being passed to that dueDate. But dont worry, as jBPM helps you alot with this part :)

Duration duration = new Duration("10 business hours"); 
dueDate = businessCalendar.add(new Date(), duration);   

//and the start again
workflowParameters.put("dueDate", dueDate);
workflowService.startWorkflow(def.id, workflowParameters);

I hope i can write the next time very sooner as it is by now…

JBPM 4 - A New Tale… With To Much Obstacles (right now)

Well, its been a while i´ve cryed out so much terrible words as by now.

JBPM 4 is cool in many details, especially the Service-API (i guess its stolen from Alfresco, its biggest implementor i guess).

Yesterday - on Sunday - i´ve tried to implement my custom task-logic from JBPM 3… i saw the new TaskService API for this case to take use of it. Couldnt be easier, isnt so?

taskService.setVariables("taskId", taskVariablesAsMap);

“Considered it done” - ive said to me yesterday but the expected results turns into a little journey into forum-posts, commentations as well as heavily reading of the current userguides/developer guides. Because of what manner?

Well, the task-variables wont be task-variables as these variables will be propagated to the processinstance. So this means in brief: all task can have access to these variables. So theres no scoping yet available to let it say that some variables should be only - AND THIS MEANS JUST ONLY - locally managed task-variables, so multiple variables with the same name can not be overwritten by itself. By now this will be happen if you got more than one task in your process-definition. That really sucks guys - sorry!

Excerpted from the userguide i read following about this (http://docs.jboss.com/jbpm/v4.0/userguide/html_single/#taskservice):

Tasks can read and update process variables. Later tasks will have the option to declare task-local process variables.

Well done… i´ve to implement scoping for my own as long as JBoss does not scoring this big disadvantage today.

Well dont understand me in the wrong-case! I love what they do, its pretty fine but i hope it will be fixed as soon as possible due to the current release-plan so move on guys, heeejaaaaa!

Stay Tuned on Oracle-Magazine (DOAG)

Well met.

Next days  a new Article gets released which i´ve wrote some months ago. The article handles about ECM, particulary catches-up the Performance-Corner, focussing Alfresco in association with the State-Of-The-Art Database Oracle.

The main question where the most time will be spended in the article belongs to the issue on how sophisticated databasas can help us to achieve a better performance using ECM-Systems. Thats not far from business i guess even you thing yet so! Because if you looking through the wide-spreaded scape of DMS/ECM-Systems you dont see so many Systems which have the opportunity on being fast ;-) Well most business-customers doesnt care about such a manner as long as the business gets slowed down (4 Seconds to wait for one operation is okay if you have millions of documents with versioning and a much higher amount of corresponding metadata). The Kasus Knaxus here is, in which way can we tune the ECM-System by default and how can a Enterprise-Database like Oracle assist us to monitor the performance and how to optimize the whole system. Is this possible at all? Are we lost in the mailstream of Enterprise-Frameworks, Business-Usecases that can not be adopted to a ECM-System without big performance-changes?

Some things you would probably learn on reading this article being published on August 14 2009 in the magazin of the community of Oracle in Germany.

Just married: Alfresco & VTiger

Very well. On my work some people are in fraud with its business-contacts that must be managed twice: VTiger (a CRM-TOOL) as well as in Alfresco. We´ve had looking for a cool solution that brings together all those peaces to get rid of the management-overhead. And we found… nothing… realy strange i guess as i guess that both tools will be used more frequently and in some cases together. Why there exists no free-solution to fetch data from vTiger into Alfresco and vice-versa(okay first way is unidirectional towards Alfresco)

Okay, i´ve enough spoked and flamed regarding that outstanding-issue.

What can we do to get marriaged both worlds? Well we using Alfresco´s nice connector-api to solve the whole problem. The way to achieve an one-way synchronisation descripes only the way from vtiger towards alfresco. So Alfresco posses after a synchronisation more data than before ;-D

I´ve tested my basic-authentication as well as fetching of data with Alfresco 3.2 as well as vTiger-CRM Version 5.1.0

Steps i want to introduce:

1. Defining of the vTiger-Authenticator
2. Authentication with vTiger
3. fetching of Leads/Contacts

At first, we have  to setup the connector, thus knows alfresco which location must be taken to connect with a particular (Web-)Service. Therefor we add following lines to the file tomcat/shared/classes/alfresco/web-extension/webscript-framework-config-custom.xml following lines:

<config evaluator="string-compare" condition="Remote">
  <remote>
    <endpoint>
      <id>vTiger</id>
      <name>vTiger</name>
      <description>vTiger vTiger vTiger</description>
      <connector-id>http</connector-id>
      <endpoint-url>http://localhost:82</endpoint-url>
      <identity>none</identity>
    </endpoint>
  </remote>
</config>

Next step descripes the setup for the spring-context. If you have sucesfully done this step you are able to retrive informations about vTiger in your whole application. In my case i adding a quite other way on implementing a webscript (but that doesnt matter at all):

<bean id="webscript.de.dmc.VTiger.get" class="de.dmc.alfresco.VTigerWebScript" parent="webscript">       
  <property name="scriptRemote" ref="webscripts.script.remote" />  
</bean>

Now its time to implement most important functionality.

Firstly, i obtain the vTiger-Connector being defined in the file webscript-framework-config-custom.xml:

ScriptRemoteConnector vTigerConnector = scriptRemote.connect("vTiger");

Next we have to get a valid sessionId, so we can start quering the database of vTiger. As you have to know that vTiger-Authentication is using a chalange-response-mechanism to avoiding password-sending. But its nothing to worring about: its quite simple. What for ingredients we must own:

A valid Access Key: that key will be encrypted with an computed-number (token) from serversite. You can find this key in you user-account in vTiger.

A username: surely you need this part ;-D

You have to know about vTiger that the WebService-Protocoll is based on REST and simple HTTP-mechanism. The returned value from vTiger is in every case a JSON-Object. Oh did i had say in every case? In some circumstances you get nothing back if you got made some errors … really bad.

String key = "wJAsUpRC6Bp5qKm3";Response response = connector.call("/webservice.php?operation=getchallenge&username=admin");
JSONObject resultObject = new JSONObject(response.getResponse());
resultObject = resultObject.getJSONObject("result");Map<String, String> data = new HashMap<String, String>();
data.put("operation", "login");
data.put("username", "admin");
data.put("accessKey", md5(resultObject.get("token").toString() + key));
String postBody = "";
boolean isFirst=true;
for(Map.Entry<String, String> entry : data.entrySet()){
  if(!isFirst)

  postBody+="&";
  postBody+=entry.getKey()+"="+entry.getValue();
  isFirst = false;
}

response = connector.post("/webservice.php", postBody, "application/x-www-form-urlencoded");
resultObject = new JSONObject(response.getResponse());

//returns the sessionKey
return (String)resultObject.getJSONObject("result").get("sessionName");

public String md5(Object obj){

  String toEnc = new String(obj.toString());
  MessageDigest mdEnc = null;

  try {
    mdEnc = MessageDigest.getInstance("MD5");
  }
  catch (NoSuchAlgorithmException e) {
    throw new RuntimeException(e);
  }

  mdEnc.update(toEnc.getBytes(), 0, toEnc.length());

  return new BigInteger(1, mdEnc.digest()).toString(16);
}

In my depicted example i want to get a valid authenticaten with an admin-account so i take use of the user “admin”.

The returned value is nothing less than the sessionId. Ever preceeding call must posses this sessionId on adding this part as a param/value-pair upon the url.

Last step we have to go is to retrieving - for instance - the list of contacts in vTiger.

org.alfresco.connector.Response response = connector.call("/webservice.php?operation=query&query=" + org.alfresco.util.URLEncoder.encode("select * from Contacts;") + "&sessionName=" + sessionKey);return new JSONObject(response.getResult());

We are done… the next steps are quite simple as you got the data already. Subsequent doings on adding persons based on Leads/Contacts being stored in vTiger are the easiest part.

Alfresco 3.2 Share: Pimp The Document-Library for Custom Document Types

What we´ve seen from my last post about the tales through the features of the newest Alfresco Version was just the first trick. The second trick belongs to the documentLibrary of share: How can we pimp the document-library for our custom Document-Types? Well, if we want to provide additional menu-items - to obtain just a document-list that belongs to one document-type, we have to configure and extend alfresco in both directions:

  1. Alfresco Explorer
  2. Alfresco Share

The left displayed image gives you a first imagination we want to implement the next steps.

When calls arriving Alfresco with the aim to retrieve a bunch of documents they will be processed by a WebScript that is mapping some JavaClasses in its JavaScript-Code. These classes are responsible to retrieve the results on using Alfresco-Service-API. Following example shows up an appropriated example how you can call these “backin-classes”. For instance, the object search isnt defined in any javascript-line but via Spring.

if (args["id"] != null) {
  var id = args["id"]; 
  object = search.findNode(id);
  if (object != null && args["shortQNames"] != null && args["shortQNames"] == "true") {
    model.put = object.toJSON(true);
  }

  model.put = object.toJSON(true);

}

Within the configuration-file script-services-context.xml we can find the definition of all scriptObjects that can be used via scripting. But thats not the matter i want to discuess here - i digress regarding the main-thematic here…

If the left site, of the documentlibrary is being in construction, a call is set via proxy-connector of share towards Alfresco-Explorer. So here comes the way: the doclist.get.js will be executed where the passed arguments of the call are processed in such a way, that a lucene-query is being constructed.

filterParams = getFilterParams(filter, parsedArgs, favourites)

The method getFilterParams is defined in the same directory in the file filters.lib.js. In that file theres a switch-construct defined which checks the passed filterId (i will introduce this filterId later) to made-up the query: so here you can add you´re case-block:

      case "butchersBay":

         var filterQuery = "+PATH:\"" + parsedArgs.rootNode.qnamePath + "//*\"";

         filterParams.query = filterQuery + ' AND +TYPE:"{http://www.dmc.de/ns/dmc/1.0}butchersBay"' ;

         break;

Right here, we have defined a case-block which is executed if a filterId is passed with the name “butchersBay” - our custom model. It doesnt matter whether its a realy existing content model but its a common approach. Very well, what brings out the query we´ve just defined? All items with type of “butchersBay” gettin returned from a specificaly path (e.g. /app:company_home/st:Sites/cm:MySite/cm:documentLibrary) - nothing else.

Now after we´ve done the first step, we have to change some things within Alfresco Share. Within the file filter.get.config.xml you define the filterId that we have already added to the alfresco-part of our current tale: the “butchersBay”-filterid:

<filter id="butchersBay" label="link.butchersBay" />

Now we´ve defined the filter which will be recognized by share on restart or on using the “Refresh WebScript”-Functionality. Now its time to add the language-part of that filter so we get displayed a human-readable text in the left pane of the documentlibrary. Therefore we open the file filter.get.properties and add the label link.butchersBay with an appropriated text. Very well done!

We´re ready for Takeoff. Test it guy!

Alfresco 3.2 Share: FormService Seems To Be cool. But Whats About Associations?

Alfresco 3.2 bears new cool features to the community, especially an easy way to display custom metadata in Share. Actually it was´nt possible, displaying custom metadata-properties in Share without doing customizations on the underlying Share/SURF-Code.

Well these times are over … almost over!

If you using an association between two nodes, you get not the same feeling about the result as you probably though about it. Because if you looking to you´re document-library in Share, you will receive just a node-reference to the property-association. Oh thats fairly crappy but i guess, its just a temporary problem until Alfresco drops out the next version. Well, in the meantime we have to solve this issue going another way.

The following approach likey differs from a great customizations so we expect to get the solution in less then a few minutes.

At first i will show you my contentmodel i´ve been extended. This content-type is called “myModel”:

...
<associations> 
   <association name="dmc:contactPerson">
      <source>
         <mandatory>false</mandatory>
         <many>true</many>
      </source>
      <target>
         <class>cm:person</class>
         <mandatory>false</mandatory>
         <many>false</many>
      </target>
   </association>
</associations>
...

I´ve just added an association to a person that is targeted as “contact-person”. Using Alfresco-Explorer all works fine and you are able to select a person. Following image depicts our newly created association with an assigned contact-person:

Cool!

If you have such a document-Type in your documentlibrary of share stored, its likely normal to display this property as well.

So, therefore its time to add this newly added property of the the model “myModel” to Share. Therefore we create the file tomcat/shared/classes/alfresco/web-extension/web-framework-config-custom.xml:

...
   <show id="dmc:contactPerson" for-mode="view"/> 
</field-visibility>
<appearance>
   <field id="dmc:contactPerson">
      <control template="/org/alfresco/components/form/controls/association.ftl" />
   </field>

Now this gives a show-up of the the nodeRef as i´ve descriped earlier in that post. Thats not the solution we want.

Change the control-tag attribute to following value:  /org/alfresco/components/form/controls/association_person.ftl

Next we have to extend the form.get.js, responsible for managing all form-properties in Alfresco-Share.

Next we will edit this file, starting with method setupField:

...

 // setup text for the field i.e. the label, description & help
setupFieldText(fieldDef, fieldConfig);// setup constraints for the field

setupFieldConstraints(fieldDef, fieldConfig);

// setup the value for the field
setupFieldValue(formModel, fieldDef, fieldConfig);
//thats the new line of code we´ve just added here
//setup associations for the field
setupAssociations(formModel, fieldDef, fieldConfig);

At the bottom of this file we add the corresonding method:

function setupAssociations(formModel, fieldDef, fieldConfig){
   if(fieldDef.type !== "association")
     return;

   connector = remote.connect("alfresco");
   json = connector.get("/webframework/content/metadata?id=" + fieldDef.value);

   try {

     fieldModel = eval('(' + json + ')');

     if(json.status == 200) {

       props = new Array();

       for (key in fieldModel.properties) {
          trimmed_key = key.substring(key.indexOf('}')+1,key.length)
          props[trimmed_key] = fieldModel.properties[key];
       }

       fieldDef.assocProperties = props

   }
}

 catch(e){
    logger.getSystem().out( e );
}

}

Thats all, we got to do. The method calls the server back due to retrieve more informations about the assosciation-nodeRef. We just call another alfresco-rest-script. Even though this method is not realy the best peace of code i´ve wrote the last years ago, we expect almost a fast solution. For instance, the fully qualified definition-names of all properties will be ereased as freemarker can not handle simplehashmaps with special-chars like ‘}’. So this should be fixed on mapping the fully qualified qnames with its corresponding short-names with character-replacing of ‘:’ to ‘_’.

Finaly we´ve to create a file being called association_person.ftl in /org/alfresco/components/form/controls/association.ftl  for displaying the appropriated association-property :

<#include "common/picker.inc.ftl" />

<#assign controlId = fieldHtmlId + "-cntrl">
  <div class="form-field">
    <#if form.mode == "view">
      <div id="${controlId}" class="viewmode-field">
        <#if field.endpointMandatory && field.value == "">
           <span class="incomplete-warning"><img src="${url.context}/components/form/images/warning-16.png" title="${msg("form.field.incomplete")}" /><span>
        </#if>
        <span class="viewmode-label">${field.label?html}:</span>
        <span id="${controlId}-currentValueDisplay" class="viewmode-value current-values">
           <a href="${url.context}/page/user/${field.assocProperties.userName}/profile">${field.assocProperties.firstName} ${field.assocProperties.lastName}</a>
        </span>
      </div>
    </#if>
</div>

We are done. Try it on refreshing your Share-Webscripts! Its even possible to click on the contactperson where the profile-site of this person gets displayed.

Re-Attaching Hibernate-Objects In New Transaction

Well i lovin it, using actionListener of JSF as the results of it is nothing less than the object itself, stored as a parameter of a UICommandButton or UICommandLink. The other thing is using direct mapping of values to input-elements.

For instance, following line gives me the whole object back:


 
	value=”#{WorkflowManager.taskInstances}”
	rows=”15″ columnClasses=”tableCol”>
	
                
		    
		
	        
	
      ….

Well if i want to save this current change of the name (do you see the inputText in the code, äh?), normaly you write following lines of code to achieve this:

...
Object ret = getHibernateTemplate().get(WorkflowPersistenceTemplate.class, persistenceTemplate.getId());
if (ret == null)
    id = (Long) getHibernateTemplate().save(persistenceTemplate);
else {
    id = persistenceTemplate.getId();
    getHibernateTemplate().update(merge);
}
  ...

So, the persistenceTemplate is the same object we have seen in the first code-snippet. I dont want to rebuild all of that peace of informations each time of HttpRequest to made up a new object - whats the time hu? In place of sucessfuly saving of the workflowtemplate we get punished with following exception:

Caused by: org.hibernate.NonUniqueObjectException: a different object with the s
ame identifier value was already associated with the session: [com.logicaldoc.wo
rkflow.persistence.WorkflowPersistenceTemplate#2]
        at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(State
fulPersistenceContext.java:590)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdat
e(DefaultSaveOrUpdateEventListener.java:284)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDeta
ched(DefaultSaveOrUpdateEventListener.java:223)
        at org.hibernate.event.def.DefaultUpdateEventListener.performSaveOrUpdat
e(DefaultUpdateEventListener.java:33)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpda
te(DefaultSaveOrUpdateEventListener.java:70)
        at org.hibernate.impl.SessionImpl.fireUpdate(SessionImpl.java:564)
        at org.hibernate.impl.SessionImpl.update(SessionImpl.java:552)
        at org.hibernate.impl.SessionImpl.update(SessionImpl.java:544)
        at org.springframework.orm.hibernate3.HibernateTemplate$14.doInHibernate
(HibernateTemplate.java:715)
        at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(Hibern
ateTemplate.java:419)
        ... 67 more

Why does hibernate bother us with this simple operation? Well if you receive this error, you have ran into the same problem as the rest of developers-world. If you load a object from the database into you application, Hibernate stores this in the Session-Cache. Hibernate supports transactions and in the most cases, one transaction is exact so lang as a request is done to the server. For instance, in my application i´ve got a transaction-intercepter added through spring, so a transaction-template will be used to commit/rollback a transaction after each request.

But you have another cache in your application being called your JSF-Brain. So, if you JSF-TreeComponent is in rebuild (a new HttpRequest is done), the already existing object in jsf will be used. Actually you work with an detached hibernate object!
If you storing this object into your database (see code-snippet two) you receive the already depicted errormessage.

So how can you “reattach” you object to the hibernate session? How can we put some candies to hibernate to make him happy? By simply using the merge-method of hibernate!

WorkflowPersistenceTemplate merge = (WorkflowPersistenceTemplate)getHibernateTemplate().merge(persistenceTemplate);

So, if you have done this, you have an attached object within the hibernate-session with you current values you´ve probably netered in the mean time! Merging does nothing more than obtaining the eventually available object in the session and applying the new values on it. You receive the “old” attached object with the new values.

Save it now before its gettin detached!! ;-D

Stay Tuned On it-republik.de

Today it was a realy “relaxing” day for me at work… it was just like dreaming about the mention to send a REALY private message to a customer rather than to send it to a friend! Yes that was a strike!

But for my relief the customer wasnt angry rather than more ugly about this. What a lucky guy am i? ;-)

So this wasn´t not the main content here. Another big thing i could finish and blow away today: my article-series on it-republik.de

The thematic handles about an easy way to link-up external components on a centralized page to start interaction with its parts. I just talking about Portal-Technology with respect to Liferay. I´m talking about an easy way to connect-up alfrescos document-view in liferay on implementing two portlets with Richfaces-Power.

Obstacles will be introduced and discussed at the second part of the article-series. I hope for an urgently release!

Curb the Belly of the Beast: Drag & Drop ServerRequest-Hell And Icefaces

Icefaces supports drag-and-drop functinality regarding its component-library. For sure its easily to implement with much more issues afterwards. Some things brought me almost to cry. If you have a droplistener on your dropArea, your calling event does probably  not bearing your dragged value.



#{workflowTask.name}

Drop Target 1

As you can see, the dropping zone posseses an appropriated dropListener. The regarding Java-Code seems correct for me as well:

   public void addTaskDestinationToTransition(DropEvent event) {
		if (event.getEventType() == DndEvent.DROPPED) {
            String targetId = event.getTargetClientId();
            if ((targetId != null)) {

               WorkflowTask  workflowTask = (WorkflowTask)((HtmlPanelGroup) event.getComponent()).getDragValue();
              ...
            }
        }
	}

But it doesnt matter what i do, the DragValue seems alway be null. Its a bug in IceFaces 1.7.2SP1. Well, be smart, and add instead a dragListener that makes somethin similary. Simply add a dragListener to the dragged component and change the argument of the java-method to DragEvent.

If its done, you run into another problem that seems much harder for me.The dragged component (if its in a drag-state on push the component away from its current place) reverts its state after a few seconds without doing anything. You just holding down the mouse on the left mouse button and moving it on the page up and down…

How can we curbing this issue? Well, at first you have to grasp mostly every reaching of a dropping zone or even moving of the dragging-component invokes an AJAX-Request. And you know, you move the mouse not in everycase straigh forward to the finish-line but more in “flowing-movements” up and down. This increases excessively Pages-Requests that must be avoided. In most cases you dont have an “localhost-infrastructure” rather than a WAN-Landscape wher people will connecting to youre site from india or australia. Its a pidy about that tcp-packet-exchange!!

Well, for me i have implied that this problems belongs to this AJAX-problematic. So if we can stop sending traffic-jam to Skynet we can probably farily increasing our drag-and-drop behaviour.

Icefaces comes along with “sendmasks” which nothing less then descriptive flags about information-states that have to be sent to the server. For instance, if you want to know when a user starts an dragging-operation, this can be exposed as such a flag. Normaly you dont want bother the server (and your self) with such logentries. The only thing you likely want to know is WHAT you´ve dropped- not WHEN OR WHO. So therefore we using the attribute dragMask in every dragging-component to constraining the send-behaviour:



#{workflowTask.name}

keep looking »