cancel
Showing results for 
Search instead for 
Did you mean: 

Dynamic contraint loading query with searchService

anita_platos
Champ in-the-making
Champ in-the-making
I am trying to have a constraint loading its data through a searchService-query. The problem is that when I start the Alfresco, it keeps locked in the query, but it never starts.
This is the code I´m using:
- The java code for constraint:

package org.myproject.mycontraints;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchService;

public class LoadingMyCombo extends ListOfValuesConstraint {
    private static NodeService nodeService;
    private static SearchService searchService;

    @Override
    public void initialize() {
    }

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

    private List<String> getSearchResult()
    {
        List<String> allowedValues = new ArrayList<String>();
        String query ="PATH:\"/app:company_home/cm:DOCUMENTS\"";
        ResultSet resultSet = searchService.query(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, SearchService.LANGUAGE_SOLR_FTS_ALFRESCO, query);
        for (ResultSetRow row : resultSet)
            allowedValues.add((String)nodeService.getProperty(row.getNodeRef(), ContentModel.PROP_NAME));

        Collections.sort(allowedValues);

        if (allowedValues.size() == 0)
            allowedValues.add("");

        return allowedValues;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void setAllowedValues(List allowedValues) {
    }

    @Override
    public void evaluateCollection(Collection<Object> collection) {
    }

    public void setNodeService(NodeService nodeService) {
       LoadingMyCombo.nodeService = nodeService;
    }

    public void setSearchService(SearchService searchService) {
       LoadingMyCombo.searchService = searchService;
    }

}

- The constraint declared in the model:

   <constraint name="prfx:load-my-combo" type="org.myproject.mycontraints.LoadingMyCombo" >
         <parameter name="allowedValues">
               <list>
               </list>
         </parameter>
         <parameter name="caseSensitive"><value>true</value></parameter>
   </constraint>

- The bean to associate with the nodeService

   <bean id="mytests.myconstraints.ConstraintInitializer" class="org.myproject.mycontraints.LoadingMyCombo">
      <property name="nodeService">
         <ref bean="nodeService"/>
      </property>
      <property name="searchService">
         <ref bean="searchService"/>
      </property>
   </bean>

Somebody knows if I´m doing something wrong or why it gets locked indefinitely  in the line where it executes the query?. I know that the query is well-done because I tested OK using the Node Browser console.
Thank you in advance
10 REPLIES 10

anita_platos
Champ in-the-making
Champ in-the-making
The fact is that the java code with the query is called when the Alfresco is still starting - I don´t know why, for indexing, cache.. -. This queryes fails because the searchService needs Alfresco already started up, so I think this is the reason because it fails. If I use a counter in my java class to prevent calling the method the first times - while it´s starting -, it will do right once the Alfresco is started. I don´t like this solution because it is far from ellegant although it works..If somebody have a better idea, please let me know,
Thank you

kaynezhang
World-Class Innovator
World-Class Innovator
Why do you want to use a dynamic list of values constraint, if you just want to let the user choose a value from a dropdown list or a combo box,you should customize alfresco share ui instead of dictionary model.
Frequently modify dynamic list of constraints(especially remove item from your constraints)  may lead repository into a invalid state.
If you really want to do it in your way ,make your ListOfValuesConstraint implements ApplicationContextAware interface,and get NodeService and SearchService from spring ApplicationContext .



import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class LoadingMyCombo extends ListOfValuesConstraint  implements ApplicationContextAware{

   private static  ApplicationContext applicationContext;
   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
      this.applicationContext = applicationContext;
   }
   @Override
   public void initialize() {

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

   private List<String> getSearchResult()
   {
      NodeService nodeService =(NodeService)applicationContext.getBean("alfresco NodeServiceid");
      SearchService searchService = (SearchService)applicationContext.getBean("alfresco searchServcieid");
      List<String> allowedValues = new ArrayList<String>();
      String query = "PATH:\"/app:company_home/cm:DOCUMENTS\"";
      ResultSet resultSet = searchService.query(
            StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
            SearchService.LANGUAGE_SOLR_FTS_ALFRESCO, query);
      for (ResultSetRow row : resultSet)
         allowedValues.add((String) nodeService.getProperty(
               row.getNodeRef(), ContentModel.PROP_NAME));
      Collections.sort(allowedValues);
      if (allowedValues.size() == 0)
         allowedValues.add("");
      return allowedValues;
   }

Thank you for reply me kaynezhang. Maybe I am wrong, but I think that the difference between your code and mine is that you use the ApplicationContextAware to get the
nodeService and searchService, while I do it putting the parameters in the bean. I don´t think that it´s gonna be relevant in the fact of having or not inconsistences.
  Moreover, I have 2 problems:
1. The most important. How can I get the current node in the java constraint code?. At least, I need to read a property of the node - it´s a read-only protected
property, so I don´t need to do it like cascade interdependences  refreshing and doing things like that.
2. I don´t know why, but the method getSearchResult() is called some times while Alfresco is starting - maybe for indexing or cache, I don´t know -. The problem is
that it gets locked indefinetly in the point of the query - I guess that it´s because it makes a mess trying to do a query without having finally started the content server -. Likewise I tryed with your code and it occurs the same.
I have figured out this problem doing something far from ellegant, with a counter to say - don´t do nothing the first 3 times when Alfresco is starting.
As simple as this:

    public List<String> getAllowedValues() {

         conta++;
         P.p ("getAllowedValues() "+conta);
         
          if (conta<4)  allowedValues = getEmptyList ();
          else     allowedValues = getSearchResult();
           super.setAllowedValues(allowedValues);
           return allowedValues;
    }

private List getEmptyList ()
       {
           List valuesResult = new ArrayList();
           valuesResult.add("");
           return valuesResult;
       }

This solution is not very pretty but is works OK doing it, if somebody knows any other way to fix it, please let me know,
Than you

shubhada
Champ in-the-making
Champ in-the-making
Hi Kaynezhang and Anita
I am loading a aspect which is a contraint of country. I have palced it in path , Path= ""/app:company_home/cm:metadatalist""
On startup of alfresco , with serach service am running the query to read this file. And it is stuck and not processing as search service is not avialable before startup.

I am trying to add some more country values to the list in run time, so that it gets reflected  in the country dropdown while saving a content without restart of server.
As Anitha said, if I put a condition that count till 4, dont search for file while restarting.That works fine. But I dont want to hardcode any count value.
Can you please guide in achieving this ?

Thanks,

kaynezhang
World-Class Innovator
World-Class Innovator
Sine you implements a dynamic list of constraints like this ,then some one can change your dynamic list of constraints by adding/modifying/deleting node. Adding nodes will not be a problem, but deleting nodes will leave nodes with this property value in an invalid state.

I think the reason why it gets locked indefinetly in the point of the query is because during alfresco startup the search component is busy doing some initialization work ( for example checks consistence between the metadata, indexes and content) and not ready to provide search searvice.

You can try to define your bean like this

   <bean id="mytests.myconstraints.ConstraintInitializer" class="org.myproject.mycontraints.LoadingMyCombo" depends-on="repositoryEndBootstrapBean">

Or you can just deploy your custom model into Company Home/Dictionary/Models in Alfresco repository instead of deploying content model XML file in classpath

Thank you again, but it doesn´t work anyway. It tryes to do the queries while the repository is starting eitherway, even I try putting the depends-on="repositoryEndBootstrapBean" in the constaint definition and neither. That´s not my priority because I figure out with the counter - resolutive although not ellegant -.
My main problem is to get the node. I have seen some code in internet that does something like this:


import org.alfresco.web.bean.repository.Node;

public Node getNode() {return node;}
public void setNode(Node node) {this.node = node;}


What do I have to do to get the node?. It catch me as null, but I don´t know how does it work!

kaynezhang
World-Class Innovator
World-Class Innovator
I'm sorry I am not clear which node do you want to get?
org.alfresco.web.bean.repository.Node is used in web-client .
If you get a NodeRef ,then you construct a org.alfresco.web.bean.repository.Node like this


import org.alfresco.web.bean.repository.MapNode;
import  org.alfresco.web.bean.repository.Node;

  MapNode node = new MapNode(nodeRef);

Ok kaynezhang, I changed my mind radically in the way to figure out the requirement: I was thinking what you told me about inconsistences risks using constraints so I decided to avoid touching models in the alfresco core and instead of it implement new ftl controls to be used in the alfresco share that makes the queries and get the values by Web Scripts. I think this is better, more flexible and more secure than touch the alfresco core, models, constraints… Anyway thank you so much kaynezhang, you have shown me the right way :-))

kaynezhang
World-Class Innovator
World-Class Innovator
You are welcome.
If you just want to let the user choose a value from dynamic list of options ,it is a ui problem not a dictionary problem.Solving it by customizing UI is a good option,goodluck.