cancel
Showing results for 
Search instead for 
Did you mean: 

Custom Constraint

kbonnet
Champ in-the-making
Champ in-the-making
I'm a total newbie on the area of java. Nevertheless i wanted to try to create a custom constraint which implements databaselookups for a pick list. I found an example here on the forum.

I was able to get the java code compiled with javac against the Alfresco SDK. The result was a compiled .class file. I was not sure where to put it, so i put it in a new "classes" directory in my extensions root.

Next i created a test model, again based on the example i found, and i set the "type" parameter to my package name in the java code, extended with the name of the public class in the java code. In my case "org.contezza.customConstraints.ListOfValuesQueryConstraint".

Of course it did something wrong. When i try to deploy the model (it's a dynamic model in the data dictionary/models folder) i get the error message in the logging "Constraint type 'org.contezza.customConstraints.ListOfValuesQueryConstraint' on constraint 'test:CodeLabel' is not a well-known type or a valid Constraint implementation".

Because i was able to compile the java code against the SDK without error, i think this error has to do with the place i put the class file in. Can anyone give me a push into the right direction?

My environment is:
- Ubuntu 7.04
- Tomcat 5.5
- JDK 1.5
- MySQL 5

My (example) java code is as follows:


package org.contezza.customConstraints;

import java.util.ArrayList;
import java.util.List;
import java.sql.*;
//import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
import org.alfresco.web.bean.generator.BaseComponentGenerator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;
import javax.faces.model.SelectItem;

public class ListOfValuesQueryConstraint extends ListOfValuesConstraint implements Serializable {

   private static Log logger = LogFactory.getLog(BaseComponentGenerator.class);

   private static final long serialVersionUID=1;

   private List<String> allowedLabels;

   public void setAllowedValues(List allowedValues) {}
   public void setCaseSensitive(boolean caseSensitive) {}

   public void initialize() {
       super.setCaseSensitive(false);
       this.loadDB();
    }

   public List<String> getAllowedLabels() {
      return this.allowedLabels;
   }

   public void setAllowedLabels(List<String> allowedLabels) {
      this.allowedLabels=allowedLabels;
   }

    public List<SelectItem> getSelectItemList() {
      List<SelectItem> result = new ArrayList<SelectItem>(this.getAllowedValues().size());
      for(int i=0;i<this.getAllowedValues().size();i++) {
         result.add(new SelectItem((Object)this.getAllowedValues().get(i),this.allowedLabels.get(i)));
      }
      return result;
   }

    protected void loadDB() {

       String driverName = "org.gjt.mm.mysql.Driver";
        String serverName = "localhost";
        String mydatabase = "alfresco";
        String username = "alfresco";
        String password = "alfresco";

        List<String> av = new ArrayList<String>();
        List<String> al=new ArrayList<String>();


        try {
           Connection connection = null;
            Class.forName(driverName);
            String url = "jdbc:mysql://" + serverName +  "/" + mydatabase;
            connection = DriverManager.getConnection(url, username, password);
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery("select code,label from codelabel");
            while (rs.next()) {
                av.add(rs.getString("code"));
                al.add(rs.getString("label"));
            }
        }
        catch (Exception e) {}

      super.setAllowedValues(av);
      this.setAllowedLabels(al);
   }
}

My example model is as follows:

<?xml version="1.0" encoding="UTF-8"?>

<model name="test:test" xmlns="http://www.alfresco.org/model/dictionary/1.0">
   <description></description>
   <author>Contezza InformatieManagement</author>
   <version>0.1</version>
   <imports>
      <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
      <import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" />
   </imports>
   <namespaces>
      <namespace uri="http://www.contezza.nl/model/test/1.0" prefix="test" />
   </namespaces>


<constraints>
   <constraint name="test:CodeLabel" type="org.contezza.customConstraints.ListOfValuesQueryConstraint">
      <parameter name="allowedValues">
         <list>
         </list>
      </parameter>
   <parameter name="caseSensitive"><value>true</value></parameter>
</constraint>
   </constraints>
  
   <types>
      <type name="test:codecontent">
         <title>Contenu étendu</title>
         <parent>cm:content</parent>
         <properties>
            <property name="test:codestr">
               <title>Code str</title>
               <type>d:text</type>
               <constraints>
                  <constraint ref="test:CodeLabel" />
               </constraints>
            </property>
         </properties>
      </type>
   </types>
</model>
27 REPLIES 27

alex--70
Champ in-the-making
Champ in-the-making
Thank acis.
The example run correctly, but this list is static, in order to apply changes from database, i have to restart alfresco.
I have try to modify the getAllowedValues metod, as you told, but nothing.

Have you other ideas ?

Thansk lot
alex–70

acis
Champ in-the-making
Champ in-the-making
I didn't check the suggestion I gave so I don't know if it's working.

but it's strange that the list is not refreshing if you are calling back the loadDb function because the allowedValues list is changed in taht function

maybe you can check if the web interface don't have the list in cache and try to refresh it

alex--70
Champ in-the-making
Champ in-the-making
I have refresh the page but the result is that the list remain with same values (static value)
I used the followed code :

public List getAllowedValues() {
      this.loadDB();
      super.getAllowedValues();
}

Can you try your code ?

Thank a lot

alex--70
Champ in-the-making
Champ in-the-making
Questiong for "msvoren" , you had the my same problem.

Have you put  the new item into the custom constraint (combo box) after reload the record from database ?

Thanks

alex–70

marcostopper
Champ in-the-making
Champ in-the-making
How can I force the refresh from db (this.loadDb()) without user interact???

Where I have to put the loadDb call?

I need to write a property by web service code. I write the value I need but if the database changes I got an error. The writing work well if I click on dropdownlist to force the values list to refresh with database value. How can I force the refresh (constraint values) itself (without clikking on the dropdown list? Where I have to put the call "this.loadDB()"??

Please help me.

Thanks!


package org.contezza.customConstraints;

import java.util.ArrayList;
import java.util.List;
import java.sql.*;
//import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
import org.alfresco.web.bean.generator.BaseComponentGenerator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;
import javax.faces.model.SelectItem;

public class ListOfValuesQueryConstraint extends ListOfValuesConstraint implements Serializable {

   private static Log logger = LogFactory.getLog(BaseComponentGenerator.class);

   private static final long serialVersionUID=1;

   private List<String> allowedLabels;

   public void setAllowedValues(List allowedValues) {}
   public void setCaseSensitive(boolean caseSensitive) {}

   public void initialize() {
       super.setCaseSensitive(false);
       this.loadDB();
    }

   public List<String> getAllowedLabels() {
      return this.allowedLabels;
   }

   public void setAllowedLabels(List<String> allowedLabels) {
      this.allowedLabels=allowedLabels;
   }

    public List<SelectItem> getSelectItemList() {
      List<SelectItem> result = new ArrayList<SelectItem>(this.getAllowedValues().size());
      for(int i=0;i<this.getAllowedValues().size();i++) {
         result.add(new SelectItem((Object)this.getAllowedValues().get(i),this.allowedLabels.get(i)));
      }
      return result;
   }

    protected void loadDB() {

       String driverName = "org.gjt.mm.mysql.Driver";
        String serverName = "localhost";
        String mydatabase = "alfresco";
        String username = "alfresco";
        String password = "alfresco";

        List<String> av = new ArrayList<String>();
        List<String> al=new ArrayList<String>();


        try {
           Connection connection = null;
            Class.forName(driverName);
            String url = "jdbc:mysql://" + serverName +  "/" + mydatabase;
            connection = DriverManager.getConnection(url, username, password);
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery("select code,label from codelabel");
            while (rs.next()) {
                av.add(rs.getString("code"));
                al.add(rs.getString("label"));
            }
        }
        catch (Exception e) {}

      super.setAllowedValues(av);
      this.setAllowedLabels(al);
   }
}

How can I force the refresh from db (this.loadDb()) without user interact???

Where I have to put the loadDb call?

I need to write a property by web service code. I write the value I need but if the database changes I got an error. The writing work well if I click on dropdownlist to force the values list to refresh with database value. How can I force the refresh (constraint values) itself (without clikking on the dropdown list? Where I have to put the call "this.loadDB()"??

Please help me.

Thanks!

buddycasino
Champ in-the-making
Champ in-the-making
we could have use the "converter=" attribute in the web-client-config-custom.xml but good luck to do it. I tried hard and it didn't work out.

Thats because you have to declare your converter in the faces-config-custom.xml. Of course, that is not undocumented but simply implied to be a known fact.
But unfortunately that won't help you either, since the converter is used for the value, not the label.
In the edit view, that is, not in the properties view, where it looks correct. Holy jesus on a bicycle….

jarrett
Champ in-the-making
Champ in-the-making
Hello,

Once I figured out the imports I was able to get this code to work, I think… I have one remaining issue to resolve and I wasn't sure if anyone else has faced this issue:

    Details page shows the label correct for the property value
    Drop downs show the label correctly in edit mode
    However, my "selected items" shows the value and not the label.


In catalina.out the warning is:

WARN  [bean.generator.BaseComponentGenerator] ListOfValuesQueryConverter could not be applied

In web-client-config-custom.xml the property is:

<show-property name="ygrd:Geography" component-generator="ListOfValuesQueryGenerator" converter="ListOfValuesQueryConverter"/>

In faces-config-custom my beans are:
<managed-bean>
        <description>Dropdown with lable and value</description>
        <managed-bean-name>ListOfValuesQueryGenerator</managed-bean-name>
        <managed-bean-class>org.contezza.customConstraints.ListOfValuesQueryGenerator</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

<managed-bean>
        <description>Dropdown with lable and value</description>
        <managed-bean-name>ListOfValuesQueryConverter</managed-bean-name>
        <managed-bean-class>org.contezza.customConstraints.ListOfValuesQueryConverter</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
</managed-bean>


Any ideas?

nikes
Champ on-the-rise
Champ on-the-rise
nice thread….

I am able to populate drop down from database table and also when I add new value in database it gets reflected in Alfresco.

norgan
Champ in-the-making
Champ in-the-making
Hi Nikes,
can you summarize your solution for us as example in the wiki and post a link here ? Idealy, you can put your lessonslearned in there as well ?

That would be great,
Norgan

nikes
Champ on-the-rise
Champ on-the-rise
Please refer below refined code. Its working properly on my implementation.


package org.customConstraints;

import java.util.ArrayList;
import java.util.List;
import java.sql.*;

import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
import org.alfresco.web.bean.generator.BaseComponentGenerator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;
import javax.faces.model.SelectItem;

public class ListOfValuesQueryConstraint extends ListOfValuesConstraint implements Serializable {

   private static Log logger = LogFactory.getLog(BaseComponentGenerator.class);

   private static final long serialVersionUID=1;

   private List<String> allowedLabels;

   public void setAllowedValues(List allowedValues) {}
   public void setCaseSensitive(boolean caseSensitive) {}

   public void initialize() {
       super.setCaseSensitive(false);
       this.loadDB();
    }

   public List getAllowedValues() {
      this.loadDB();
      return super.getAllowedValues(); // In earlier post there is no return statement..
     //return this.getAllowedValues();
}

   public List<String> getAllowedLabels() {
      return this.allowedLabels;
   }

   public void setAllowedLabels(List<String> allowedLabels) {
      this.allowedLabels=allowedLabels;
   }

    public List<SelectItem> getSelectItemList() {
      List<SelectItem> result = new ArrayList<SelectItem>(this.getAllowedValues().size());
      for(int i=0;i<this.getAllowedValues().size();i++) {
         result.add(new SelectItem((Object)this.getAllowedValues().get(i),this.allowedLabels.get(i)));
      }
      return result;
   }

    protected void loadDB() {

       String driverName = "org.gjt.mm.mysql.Driver";
        String serverName = "localhost";
        String mydatabase = "alfresco";
        String username = "root";
        String password = "admin1";

        List<String> av = new ArrayList<String>();
        List<String> al=new ArrayList<String>();


        try {
           Connection connection = null;
            Class.forName(driverName);
            String url = "jdbc:mysql://" + serverName +  "/" + mydatabase;
            connection = DriverManager.getConnection(url, username, password);
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery("select custName from Customers");
            while (rs.next()) {
                av.add(rs.getString("custName"));
                al.add(rs.getString("custName"));
            }
         rs=null;
        }
        catch (Exception e) {}

      super.setAllowedValues(av);
      this.setAllowedLabels(al);
   }
}