how to specify in compass (lucene) whether to store field contents? - lucene

I am trying to understand whether a legacy app that generates a compass 2.2 index, stores the contents of fields or not, I can open the index with luke.net and from my understanding it's not storing fields, it just returns an id, presumably to be used elsewhere to select from a db
see this for lucene : Lucene Field.Store.YES versus Field.Store.NO
how can I tell whether this compass application indexes with the equivalent of lucene.net Field.Store.NO
, this is the compass.cfg.xml :
<compass-core-config
xmlns="http://www.opensymphony.com/compass/schema/core-config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opensymphony.com/compass/schema/core-config
http://www.opensymphony.com/compass/schema/compass-core-config.xsd">
<compass name="default">
<connection>
<!-- index path from a file dataUpdate.properties -->
<file path="/" />
</connection>
<searchEngine>
<analyzer name="default" type="CustomAnalyzer" analyzerClass="myclass.beans.search.PerFieldAnalyzer" >
<!-- example :
<setting name="PerField-fieldname" value="org.apache.lucene.analysis.standard.StandardAnalyzer" />
<setting name="PerFieldConfig-stopwords-fieldname" value="no:" />
<setting name="PerFieldConfig-stopwords-fieldname" value="yes:aa,bb" />
-->
<setting name="PerField-symbol" value="org.apache.lucene.analysis.standard.StandardAnalyzer" />
<setting name="PerFieldConfig-stopwords-symbol" value="no:" />
<setting name="PerField-isin" value="org.apache.lucene.analysis.standard.StandardAnalyzer" />
<setting name="PerFieldConfig-stopwords-isin" value="no:" />
<setting name="PerField-tipo_opzione" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-settore_cod" value="org.apache.lucene.analysis.KeywordAnalyzer" />
<setting name="PerField-trend_medio" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-trend_breve" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-trend_lungo" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-tipo_sts_cod" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-valuta" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-sottotipo_tit" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-tabella_rt" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-market" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-cod_segmento" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-tipo_tit" value="org.apache.lucene.analysis.KeywordAnalyzer"/>
<setting name="PerField-radiocor" value="org.apache.lucene.analysis.standard.StandardAnalyzer" />
<setting name="PerFieldConfig-stopwords-radiocor" value="no:" />
</analyzer>
</searchEngine>
<mappings>
<class name="myclass.tserver.beans.search.SearchIndex" />
</mappings>
<settings>
<setting name="compass.transaction.lockTimeout" value="180" />
</settings>
</compass>
</compass-core-config>
is it that value="no:" means not to store the value, or not to consider it as "stopword" ? whereas for example value="org.apache.lucene.analysis.standard.StandardAnalyzer" means to store it
this is the analyzer it seems to use :
package myclass.tserver.beans.search;
import myclass.tserver.ejb.StubWrapper;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.PerFieldAnalyzerWrapper;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.compass.core.CompassException;
import org.compass.core.config.CompassConfigurable;
import org.compass.core.config.CompassSettings;
public class PerFieldAnalyzer extends PerFieldAnalyzerWrapper implements CompassConfigurable {
private static final String FIELD_PREFIX = "PerField-";
private static final String FIELD_CONFIG_PREFIX = "PerFieldConfig-";
private static final String STOP_WORDS_PREFIX = "stopwords-";
private static final String NO_STOP_WORDS_PREFIX = "no-stopwords-";
public PerFieldAnalyzer() {
super(new StandardAnalyzer());
}
public void configure(CompassSettings settings) throws CompassException {
for (Object obj : settings.getProperties().keySet()) {
if (obj != null && obj instanceof String && ((String) obj).startsWith(FIELD_PREFIX)) {
String field = ((String) obj).substring(FIELD_PREFIX.length());
String value = settings.getSetting((String) obj);
if (value != null) {
String stopwordsParameter = settings.getSetting(FIELD_CONFIG_PREFIX + STOP_WORDS_PREFIX + field);
String[] stopwords = null;
if (stopwordsParameter != null) {
if (stopwordsParameter.trim().toLowerCase().startsWith("no:"))
// no stopwords
stopwords = new String[] {};
else if (stopwordsParameter.trim().toLowerCase().startsWith("yes:"))
// stopwords
stopwords = stopwordsParameter.trim().substring(4).split(",");
} else
// stopwords di default dello StandardAnalyzer
stopwords = null;
try {
Analyzer analyzer = getAnalyzer(value, stopwords);
addAnalyzer(field, analyzer);
} catch (Exception e) {
new CompassException("Unable to set analyzer for field " + field + " : ", e);
}
}
}
}
}
private Analyzer getAnalyzer(String classname, String[] stopwords) throws ClassNotFoundException, SecurityException,
NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException,
InvocationTargetException {
Class<Analyzer> myclass = (Class<Analyzer>) Class.forName(classname);
if (stopwords == null) {
Constructor<Analyzer> myConstructor = myclass.getConstructor();
return (Analyzer) myConstructor.newInstance();
} else {
Constructor<Analyzer> myConstructor = myclass.getConstructor(String[].class);
return (Analyzer) myConstructor.newInstance((Object)stopwords);
}
}
}

The easiest way to know which fields are stored for a lucene document is to open the index via lucene and to read in a document and then look at the list of fields for the document. Fields that are indexed but not stored will not show up in the list of the fields for the document.
Here is an example in Lucene.Net 4.8 that I wrote for you that hopefully can give you an good idea of how to check which fields are stored for a document. The syntax for you will of course be a bit different if you are using Java rather than C# and you will be using an older version of Lucene. But this chunk of code should hopefully get you a long way there.
In this example there are two documents added each with three fields. But only two of the three fields are stored, even though all three fields are indexed. I have placed a comment in the code where you can see which fields are stored for each document. In this example only two fields for each document will be in the d.Fields list because only two fields are stored.
[Fact]
public void StoreFieldsList() {
Directory indexDir = new RAMDirectory();
Analyzer standardAnalyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48);
IndexWriterConfig indexConfig = new IndexWriterConfig(LuceneVersion.LUCENE_48, standardAnalyzer);
IndexWriter writer = new IndexWriter(indexDir, indexConfig);
Document doc = new Document();
doc.Add(new StringField("examplePrimaryKey", "001", Field.Store.YES));
doc.Add(new TextField("exampleField", "Unique gifts are great gifts.", Field.Store.YES));
doc.Add(new TextField("notStoredField", "Some text to index only.", Field.Store.NO));
writer.AddDocument(doc);
doc = new Document();
doc.Add(new StringField("examplePrimaryKey", "002", Field.Store.YES));
doc.Add(new TextField("exampleField", "Everyone is gifted.", Field.Store.YES));
doc.Add(new TextField("notStoredField", "Some text to index only. Two.", Field.Store.NO));
writer.AddDocument(doc);
writer.AddDocument(doc);
writer.Commit();
DirectoryReader reader = writer.GetReader(applyAllDeletes:true);
for (int i = 0; i < reader.NumDocs; i++) {
Document d = reader.Document(i);
for (int j = 0; j < d.Fields.Count; j++) {
IIndexableField field = d.Fields[j];
string fieldName = field.Name; //<--This field is a stored field for this document.
}
}
}

Related

Jackson UnrecognizedProperyException when parsing XML

I am trying to parse an XML where I generate the DTOs using maven-jaxb2-plugin from xsd file. But I get this exception and don't know why, everything seems alright.
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Publish_Date" (class com.compnay.package.SdnList$PublshInformation), not marked as ignorable (2 known properties: "publishDate", "recordCount"])
at [Source: (PushbackInputStream); line: 4, column: 44] (through reference chain: com.compnay.package.SdnList["publshInformation"]->com.compnay.package.domain.SdnList$PublshInformation["Publish_Date"])
Jaxb execution for the relevant xsd
<execution>
<id>tds</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemas>
<schema>
<url>xsd url</url>
</schema>
</schemas>
<generatePackage>com.company.domain</generatePackage>
<generateDirectory>${project.basedir}/domain/src/main/java</generateDirectory>
<episode>false</episode>
</configuration>
</execution>
Part of the XML file where I get the error.
<publshInformation>
<Publish_Date>08/06/2021</Publish_Date>
<Record_Count>9030</Record_Count>
</publshInformation>
Rest template Configuration
JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(false);
final XmlMapper xmlMapper = new XmlMapper(module);
xmlMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
// xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // Works when this is on
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(xmlMapper);
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_XML));
return new RestTemplateBuilder()
.setReadTimeout(Duration.ofMillis(readTimeout))
.setConnectTimeout(Duration.ofMillis(connectTimeout))
.messageConverters(converter)
.build();
Part of a Generated DTO
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"publshInformation",
"sdnEntry"
})
#XmlRootElement(name = "sdnList")
public class SdnList {
#XmlElement(required = true)
protected SdnList.PublshInformation publshInformation;
#XmlElement(required = true)
protected List<SdnList.SdnEntry> sdnEntry;
........
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="Publish_Date" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="Record_Count" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"publishDate",
"recordCount"
})
public static class PublshInformation {
#XmlElement(name = "Publish_Date")
protected String publishDate;
#XmlElement(name = "Record_Count")
protected Integer recordCount;
........
}
}
I can make it work with using xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) but I don't want to lose other data. Can anyone help me figure it out why I get unrecognizedPropertyException? I will appreciate any pointers.
I guess you are doing something before the derealization which is making your input stream empty due to which you are getting this error. I used the provided XML and seems to work fine for me:
XML:
<publshInformation>
<Publish_Date>08/06/2021</Publish_Date>
<Record_Count>9030</Record_Count>
</publshInformation>
PublshInformation.class:
#XmlRootElement(name = "publshInformation")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class PublshInformation {
#XmlElement(name = "Publish_Date")
private String Publish_Date;
#XmlElement(name = "Record_Count")
private Integer recordCount;
}
PublishMain.class:
public class PublishMain {
public static void main(String[] args) throws JAXBException, XMLStreamException, IOException {
final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("publish.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
/* final Unmarshaller unmarshaller = JAXBContext.newInstance(PublshInformation.class).createUnmarshaller();
final PublshInformation publshInformation = unmarshaller.unmarshal(xmlStreamReader, PublshInformation.class).getValue();
System.out.println(publshInformation.toString());
Marshaller marshaller = JAXBContext.newInstance(PublshInformation.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(publshInformation, System.out);*/
System.out.println(inputStream);
final XmlMapper xmlMapper = new XmlMapper();
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
PublshInformation jacksonPublish = xmlMapper.readValue(xmlStreamReader, PublshInformation.class);
System.out.println(jacksonPublish);
xmlMapper.writerWithDefaultPrettyPrinter().writeValue(System.out, jacksonPublish);
}
}
This would produce the result:
java.io.BufferedInputStream#73a28541
PublshInformation(Publish_Date=null, recordCount=null)
<PublshInformation>
<recordCount/>
<publish_Date/>
</PublshInformation>
The above code works even by using the pure JAXB. If you uncomment then it will do it using the JAXB. I used the latest jackson-dataformat-xml 2.12.4
Make your fields private.
Use the latest version of the Jackson
Ensure your input is not being used before which may become empty.
This should work I believe.

Springfox API docu with xml response- Workaround for #XmlAttribute

I have some issues setting up Springfox for usage in Swagger UI.
I got it working in general, but the XML examples which are created are partly wrong because some xml annoations are not considered by springfox.
I have these models:
#XmlRootElement(name = "ApplicatorUnits")
#XmlAccessorType(XmlAccessType.FIELD)
public class EHDTOApplicatorUnits
{
#XmlElement(name = "UnitGroup")
private List<EHDTOUnitGroup> ehdtoUnitGroups;
public List<EHDTOUnitGroup> getEhdtoUnitGroups()
{
return ehdtoUnitGroups;
}
public void setEhdtoUnitGroups(List<EHDTOUnitGroup> ehdtoUnitGroups)
{
this.ehdtoUnitGroups = ehdtoUnitGroups;
}
}
#XmlRootElement(name = "UnitGroup")
#XmlAccessorType(XmlAccessType.FIELD)
public class EHDTOUnitGroup
{
#XmlAttribute(name = "name")
private String name;
#XmlElement(name = "unit")
private List<EHDTOUnit> ehdtoUnits;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public List<EHDTOUnit> getEhdtoUnits()
{
return ehdtoUnits;
}
public void setEhdtoUnits(List<EHDTOUnit> ehdtoUnits)
{
this.ehdtoUnits = ehdtoUnits;
}
}
You see some usages of #XmlAttribute, #XmlRootElement and #XmlElement.
After adding jackson jaxb annotation introspectors (I tried different ways) the XML was partly correct, as the #XmlAttribute annotations have been considered after this step:
JaxbAnnotationModule jaxbAnnotationModule = new JaxbAnnotationModule();
jaxbAnnotationModule.setPriority(Priority.PRIMARY);
mapper.registerModule(jaxbAnnotationModule);
/*AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
AnnotationIntrospector secondary = new XmlJaxbAnnotationIntrospector(mapper.getTypeFactory()); //new JaxbAnnotationIntrospector(mapper.getTypeFactory());
AnnotationIntrospector pair = new AnnotationIntrospectorPair(primary,secondary);
mapper.setAnnotationIntrospector(pair);*/
However, the other 2 are still ignored, resulting in this example xml:
<?xml version="1.0"?>
<EHDTOApplicatorUnits>
<UnitGroup>
<name>string</name>
<unit>
<id>1</id>
<name>string</name>
<unitSystem>string</unitSystem>
</unit>
</UnitGroup>
</EHDTOApplicatorUnits>
While the real output of the API is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ApplicatorUnits>
<UnitGroup name="coefTempErrorSpan">
<unit>
<id>1</id>
<name>% span /10K</name>
<unitSystem>SI</unitSystem>
</unit>
<unit>
<id>2</id>
<name>% span /50F</name>
<unitSystem>SI</unitSystem>
</unit>
</UnitGroup>
...
</ApplicatorUnits>
You see the different naming of the root element, and also the "name" of the UnitGroup which is not an attribute in the example xml but an own child-node.
I found I can use #ApiModel(value = "ApplicatorUnits") as workaround for #XmlRootElement but what about #XmlAttribute, is there also a workaround? #ApiModelProperty does not seem to work for this case. Does somebody have an idea how to workaround this issue?

Lucene does not index some terms in documents

I have been trying to use Lucene to index our code database. Unfortunately, some terms get omitted from the index. E.g. in the below string, I can search on anything other than "version-number":
version-number "cAELimpts.spl SCOPE-PAY:10.1.10 25nov2013kw101730 Setup EMployee field if missing"
I have tried implementing it with both Lucene.NET 3.1 and pylucene 6.2.0, with the same result.
Here are some details of my implementation in Lucene.NET:
using (var writer = new IndexWriter(FSDirectory.Open(INDEX_DIR), new CustomAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED))
{
Console.Out.WriteLine("Indexing to directory '" + INDEX_DIR + "'...");
IndexDirectory(writer, docDir);
Console.Out.WriteLine("Optimizing...");
writer.Optimize();
writer.Commit();
}
The CustomAnalyzer class:
public sealed class CustomAnalyzer : Analyzer
{
public override TokenStream TokenStream(System.String fieldName, System.IO.TextReader reader)
{
return new LowerCaseFilter(new CustomTokenizer(reader));
}
}
Finally, the CustomTokenizer class:
public class CustomTokenizer : CharTokenizer
{
public CustomTokenizer(TextReader input) : base(input)
{
}
public CustomTokenizer(AttributeFactory factory, TextReader input) : base(factory, input)
{
}
public CustomTokenizer(AttributeSource source, TextReader input) : base(source, input)
{
}
protected override bool IsTokenChar(char c)
{
return System.Char.IsLetterOrDigit(c) || c == '_' || c == '-' ;
}
}
It looks like "version-number" and some other terms are not getting indexed because they are present in 99% of the documents. Can it be the cause of the problem?
EDIT: As requested, the FileDocument class:
public static class FileDocument
{
public static Document Document(FileInfo f)
{
// make a new, empty document
Document doc = new Document();
doc.Add(new Field("path", f.FullName, Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("modified", DateTools.TimeToString(f.LastWriteTime.Millisecond, DateTools.Resolution.MINUTE), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("contents", new StreamReader(f.FullName, System.Text.Encoding.Default)));
// return the document
return doc;
}
}
I think I was being an idiot. I was limiting the number of hits to 500 and then applying filters on the found hits. The items were expected to be retrieved in the order they had been indexed. So when I was looking for something at the end of the index, it would tell me that nothing was found. In fact, it would retrieve the expected 500 items but they would all have been filtered out.

Have users of activeMQ own a queue which name is the user's name

In my application, a user may create an account freely, and it needs to own a queue (or topic) to communicate 2 backend processes between them. I don't want to have to modify activemq's configuration every time that someone creates an account. I have already created a jaasAuthenticationPlugin and it works fine. Here is the relevant part of my activemq.xml file:
<plugins>
<!-- 'activemq-domain' defined in conf/login.conf -->
<jaasAuthenticationPlugin configuration="activemq-domain" />
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
<authorizationEntry queue="foobarQueue"
write="foobarGroup"
read="foobarGroup"
admin="foobarGroup"
/>
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
As you may deduct, the authentication plugin is authenticating a user (foobar in this example) and putting the user in the foobarGroup group. The AuthorizationEntry is granting read, write and admin privileges to the foobarQueue to this foobarGroup. This is working well, but now if I create a new user, I must come to this file and add a new AuthorizationEntry. Is it possible with a simple configuration line in the activemq.xml to do something like:
<authorizationEntry
queue="<% Username %>"
write="<% Username %>"
read="<% Username %>"
admin="<% Username %>"
/>
or should I write some JAAS authorization class to do that?
Finally I have written a class to handle the Authorization part. It was a bit difficult because documentation is difficult to find and I couldn't find any good example. Digging in the source code of the default LDAPAuthorizationMap was key. Anyway, the source for anyone interested:
package com.example.activemq;
import org.apache.activemq.advisory.AdvisorySupport;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.jaas.GroupPrincipal;
import org.apache.activemq.security.AuthorizationMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.HashSet;
import java.util.Set;
public class OwnedUserQueueAuthorizator implements AuthorizationMap {
private static final Log log =
LogFactory.getLog(OwnedUserQueueAuthorizator.class);
private boolean debug = false;
// the Destination will be the name of the user, and we should return that
// the group with user name has read,write and admin privileges to the
// topic/queue named like the username
// for temporary destinations, if null is returned, then everybody has
// permission.
public Set<GroupPrincipal> getTempDestinationAdminACLs() {
return null;
}
public Set<GroupPrincipal> getTempDestinationReadACLs() {
return null;
}
public Set<GroupPrincipal> getTempDestinationWriteACLs() {
return null;
}
// for persistent destinations
public Set<GroupPrincipal> getAdminACLs(ActiveMQDestination destination) {
if (debug) {
log.debug("getAdminACLs: " + destination.getPhysicalName());
}
return getACLs(destination);
}
public Set<GroupPrincipal> getReadACLs(ActiveMQDestination destination) {
if (debug) {
log.debug("getReadACLs: " + destination.getPhysicalName());
}
return getACLs(destination);
}
public Set<GroupPrincipal> getWriteACLs(ActiveMQDestination destination) {
if (debug) {
log.debug("getwriteACLs: " + destination.getPhysicalName());
}
return getACLs(destination);
}
private Set<GroupPrincipal> getACLs(ActiveMQDestination destination) {
Set<GroupPrincipal> result;
if (AdvisorySupport.isAdvisoryTopic(destination)) {
result = getACLsForAdvisory();
} else {
result = new HashSet<GroupPrincipal>();
// Destination should be something like UUID or UUID.whatever...,
// so we must add only the first component as the group principal
result.add(new GroupPrincipal(
destination.getDestinationPaths()[0])
);
}
if (debug) {
String s = "";
for (GroupPrincipal gp : result) {
s += ", " + gp.getName();
}
log.debug("groupPrincipals: " + "[" + s.substring(2) + "]");
}
return result;
}
private Set<GroupPrincipal> getACLsForAdvisory() {
Set<GroupPrincipal> result = new HashSet<GroupPrincipal>();
GroupPrincipal g = new GroupPrincipal("advisories");
result.add(g);
return result;
}
// Properties
// -------------------------------------------------------------------------
// if the <bean> definition in the activemq.xml has some
// <property name="foo" value="..." />
// defined, they will call this.setFoo($value), so, even if these get/set
// methods aren't called from here, they are really needed.
public void setDebug(String debug) {
this.debug = "true".equalsIgnoreCase(debug);
}
public String getDebug() {
return String.valueOf(debug);
}
}
The conf/activemq.xml file:
<beans ...>
...
<broker ...>
...
<plugins>
<!-- 'activemq-domain' defined in conf/login.conf -->
<jaasAuthenticationPlugin configuration="activemq-domain" />
<authorizationPlugin>
<map>
<bean id="OwnedUserQueueAuthorizationMap"
class="com.example.activemq.OwnedUserQueueAuthorizator"
xmlns="http://www.springframework.org/schema/beans">
<property name="debug" value="false"/>
</bean>
</map>
</authorizationPlugin>
</plugins>
...
</broker>
...
</beans>

Dynamic list constraint not updating in alfresco on a datalist

I tried to create a dynamic list constraint. The data in the drop down is not getting refreshed when an item is added to the database.
ListOfValuesQueryConstraint.java
package org.alfresco.ryden;
import java.util.ArrayList;
import java.util.List;
import java.io.Serializable;
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 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 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 getAllowedLabels() {
return this.allowedLabels;
}
public void setAllowedLabels(List allowedLabels) {
this.allowedLabels=allowedLabels;
}
public List getSelectItemList() {
List result = new ArrayList(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 = "com.mysql.jdbc.Driver";
String serverName = "localhost:3307";
String mydatabase = "propertyrecord";
String username = "propertyrecord";
String password = "rydenproperty";
List av = new ArrayList();
List al=new ArrayList();
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 propertyRef from propertyrecord”);
while (rs.next()) {
av.add(rs.getString(“propertyRef”));
al.add(rs.getString(“propertyRef”));
System.out.println(“value of prop pavani “+rs.getString(“propertyRef”));
logger.debug(“value of prop pavani “+rs.getString(“propertyRef”));
}
rs=null;
}
catch (Exception e) {}
super.setAllowedValues(av);
this.setAllowedLabels(al);
}
}
CustomListComponentGenerator.java
package org.alfresco.ryden;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.component.UISelectOne;
import javax.faces.context.FacesContext;
import org.alfresco.repo.dictionary.constraint.ListOfValuesConstraint;
import org.alfresco.service.cmr.dictionary.Constraint;
import org.alfresco.service.cmr.dictionary.ConstraintDefinition;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.web.bean.generator.TextFieldGenerator;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
import org.apache.log4j.Logger;
import org.alfresco.ryden.ListOfValuesQueryConstraint;
public class CustomListComponentGenerator extends TextFieldGenerator {
private static Logger log = Logger.getLogger(CustomListComponentGenerator.class);
// private String tutorialQuery =
// “( TYPE:\”{http://www.alfresco.org/model/content/1.0}content\” AND
// (#\\{http\\://www.alfresco.org/model/content/1.0\\}name:\”tutorial\”
// TEXT:\”tutorial\”))”
// ;
private boolean autoRefresh = false;
public boolean isAutoRefresh() {
return autoRefresh;
}
/**
* This gets set from faces-config-beans.xml, and allows some drop downs to
* be automaticlaly refreshable (i.e. country), and others not (i.e. city).
*/
public void setAutoRefresh(boolean autoRefresh) {
this.autoRefresh = autoRefresh;
}
#Override
#SuppressWarnings(“unchecked”)
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet, PropertySheetItem item) {
UIComponent component = super.createComponent(context, propertySheet, item);
log.info(“********************** ” + item + ” >” + component + ” >” + (component instanceof UISelectOne) + ” ” + isAutoRefresh());
if (component instanceof UISelectOne && isAutoRefresh()) {
component.getAttributes().put(“onchange”, “submit()”);
}
return component;
}
/**
* Retrieves the list of values constraint for the item, if it has one
*
* #param context
* FacesContext
* #param propertySheet
* The property sheet being generated
* #param item
* The item being generated
* #return The constraint if the item has one, null otherwise
*/
protected ListOfValuesConstraint getListOfValuesConstraint(FacesContext context, UIPropertySheet propertySheet, PropertySheetItem item) {
ListOfValuesConstraint lovConstraint = null;
log.info(“propertySheet: ” + propertySheet.getNode() + ” item: ” + item.getName());
// get the property definition for the item
PropertyDefinition propertyDef = getPropertyDefinition(context, propertySheet.getNode(), item.getName());
if (propertyDef != null) {
// go through the constaints and see if it has the
// list of values constraint
List constraints = propertyDef.getConstraints();
for (ConstraintDefinition constraintDef : constraints) {
Constraint constraint = constraintDef.getConstraint();
//log.info(“constraint: ” + constraint);
if (constraint instanceof ListOfValuesQueryConstraint) {
//Node currentNode = (Node) propertySheet.getNode();
// This is a workaround for the fact that constraints do not
// have a reference to Node.
//((ListOfValuesQueryConstraint) constraint).setNode(currentNode);
lovConstraint = (ListOfValuesQueryConstraint) constraint;
break;
}
if (constraint instanceof ListOfValuesConstraint) {
lovConstraint = (ListOfValuesConstraint) constraint;
break;
}
}
}
return lovConstraint;
}
}
custom-model.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Definition of Property Base Model -->
<model name="cdl:customdatalist" xmlns="http://www.alfresco.org/model/dictionary/1.0">
<!-- Optional meta-data about the model -->
<description>Custom Data Model</description>
<author>Lalitha Akella</author>
<version>1.0</version>
<!-- Imports are required to allow references to definitions in other models -->
<imports>
<!-- Import Alfresco Dictionary Definitions -->
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<!-- Import Alfresco Content Domain Model Definitions -->
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
<import uri="http://www.alfresco.org/model/datalist/1.0" prefix="dl"/>
</imports>
<!-- Introduction of new namespaces defined by this model -->
<namespaces>
<namespace uri="cdl.model" prefix="cdl"/>
</namespaces>
<constraints>
<constraint name="cdl:PropertyRef" type="org.alfresco.ryden.ListOfValuesQueryConstraint" >
<parameter name="allowedValues">
<list>
</list>
</parameter>
<parameter name="caseSensitive"><value>true</value></parameter>
</constraint>
</constraints>
<types>
<type name="cdl:applicationform">
<title>Custom Application Form</title>
<parent>dl:dataListItem</parent>
<properties>
<property name="cdl:applicationpropertyRef">
<title>Property Reference</title>
<type>d:text</type>
<mandatory>true</mandatory>
<constraints>
<constraint ref="cdl:PropertyRef" />
</constraints>
</property>
<property name="cdl:applicationpropAddress">
<title>Property Address</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
<property name="cdl:apcreateddate">
<title>Created Date</title>
<type>d:date</type>
<mandatory>false</mandatory>
</property>
<property name="cdl:apcreatedby">
<title>Created By</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
<property name="cdl:applicationstatus">
<title>Application Status</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
<property name="cdl:applicationlink">
<title>Application Workflow Link</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
</properties>
<associations>
<association name="cdl:applicationassignee">
<title>Assignee</title>
<source>
<mandatory>true</mandatory>
<many>true</many>
</source>
<target>
<class>cm:person</class>
<mandatory>true</mandatory>
<many>false</many>
</target>
</association>
<association name="cdl:applicationattachments">
<title>Attachments</title>
<source>
<mandatory>true</mandatory>
<many>true</many>
</source>
<target>
<class>cm:cmobject</class>
<mandatory>true</mandatory>
<many>true</many>
</target>
</association>
</associations>
</type>
<type name="cdl:terminationform">
<title>Custom Termination Form</title>
<parent>dl:dataListItem</parent>
<properties>
<property name="cdl:terminationpropertyRef">
<title>Property Reference</title>
<type>d:text</type>
<mandatory>true</mandatory>
<constraints>
<constraint ref="cdl:PropertyRef" />
</constraints>
</property>
<property name="cdl:trcreateddate">
<title>Created Date</title>
<type>d:date</type>
<mandatory>false</mandatory>
</property>
<property name="cdl:trcreatedby">
<title>Created By</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
<property name="cdl:terminationstatus">
<title>Termination Status</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
<property name="cdl:terminationlink">
<title>Termination Workflow Link</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
</properties>
<associations>
<association name="cdl:terminationassignee">
<title>Assignee</title>
<source>
<mandatory>true</mandatory>
<many>true</many>
</source>
<target>
<class>cm:person</class>
<mandatory>true</mandatory>
<many>false</many>
</target>
</association>
<association name="cdl:terminationattachments">
<title>Attachments</title>
<source>
<mandatory>true</mandatory>
<many>true</many>
</source>
<target>
<class>cm:cmobject</class>
<mandatory>true</mandatory>
<many>true</many>
</target>
</association>
</associations>
</type>
</types>
</model>
web-client-config-custom.xml
<config evaluator="node-type" condition="cdl:assignationform">
<property-sheet>
<show-property name="cdl:assignationpropertyRef" component-generator="CustomListComponentGenerator" />
</property-sheet>
</config>
faces-config-beans.xml
<managed-bean>
<description>
Bean that generates a custom generator component
</description>
<managed-bean-name>
CustomListComponentGenerator
</managed-bean-name>
<managed-bean-class>
org.alfresco.ryden.CustomListComponentGenerator
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>autoRefresh</property-name>
<value>true</value>
</managed-property>
</managed-bean>
I don't know whether I should be changing any other files or some thing is wrong in the code above.
I am new To alfresco. Any help is deeply appreciated.
Thanks,
Pavani
Try the following and change to as needed, as it works
ListOfCountriesQueryConstraint.java
package org.spectrum.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 ListOfCountriesQueryConstraint extends ListOfValuesConstraint implements Serializable {
private static Log logger = LogFactory.getLog(BaseComponentGenerator.class);
private static final long serialVersionUID = 1;
private List<String> allowedLabels;
#Override
public void setAllowedValues(List allowedValues) {
}
#Override
public void setCaseSensitive(boolean caseSensitive) {
}
#Override
public void initialize() {
super.setCaseSensitive(false);
this.loadDB();
}
#Override
public List getAllowedValues() {
this.loadDB();
return super.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 = "alfrescotest";
String mydatabase = "alfresco_custom";
String username = "root";
String password = "support";
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 country from countries");
while (rs.next()) {
av.add(rs.getString("country"));
al.add(rs.getString("country"));
}
} catch (Exception e) {
}
super.setAllowedValues(av);
this.setAllowedLabels(al);
}
}
custom-model.xml
<constraint name="sp:country" type="org.spectrum.customConstraints.ListOfCountriesQueryConstraint">
<parameter name="allowedValues">
<list>
</list>
</parameter>
<parameter name="caseSensitive"><value>true</value></parameter>
</constraint>
Make sure to copy the compile java to tomcat/webapps/alfresco/WEB-INF/classes/org/xxx/