You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lenya.apache.org by an...@apache.org on 2008/03/25 17:48:53 UTC
svn commit: r640893 - in /lenya/trunk/src/modules/lucene: ./
config/cocoon-xconf/ java/src/org/apache/cocoon/components/search/
java/src/org/apache/cocoon/components/search/components/impl/
java/src/org/apache/cocoon/transformation/ java/src/org/apache...
Author: andreas
Date: Tue Mar 25 09:48:47 2008
New Revision: 640893
URL: http://svn.apache.org/viewvc?rev=640893&view=rev
Log:
Adding all meta data and the fields 'uuid' and 'language' to the Lucene index.
Added:
lenya/trunk/src/modules/lucene/config/cocoon-xconf/metaDataFieldRegistry.xconf
lenya/trunk/src/modules/lucene/config/cocoon-xconf/queryString-module.xconf
lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/
lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/
lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/MetaDataFieldRegistry.java
lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/QueryStringModule.java
lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/impl/
lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/impl/MetaDataFieldRegistryImpl.java
lenya/trunk/src/modules/lucene/xslt/metadata2index.xsl
Modified:
lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/Index.java
lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/AbstractIndexer.java
lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/DefaultIndexerImpl.java
lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/IndexManagerImpl.java
lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/transformation/LuceneIndexTransformer2.java
lenya/trunk/src/modules/lucene/sitemap.xmap
lenya/trunk/src/modules/lucene/xslt/index.xsl
lenya/trunk/src/modules/lucene/xslt/search2html.xsl
Added: lenya/trunk/src/modules/lucene/config/cocoon-xconf/metaDataFieldRegistry.xconf
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/config/cocoon-xconf/metaDataFieldRegistry.xconf?rev=640893&view=auto
==============================================================================
--- lenya/trunk/src/modules/lucene/config/cocoon-xconf/metaDataFieldRegistry.xconf (added)
+++ lenya/trunk/src/modules/lucene/config/cocoon-xconf/metaDataFieldRegistry.xconf Tue Mar 25 09:48:47 2008
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- $Id: doctypes.xconf 164635 2005-04-25 20:01:43Z tschlabach $ -->
+
+<xconf xpath="/cocoon"
+ unless="/cocoon/copmonent[@role = 'org.apache.lenya.modules.lucene.MetaDataFieldRegistry']">
+
+ <component role="org.apache.lenya.modules.lucene.MetaDataFieldRegistry"
+ class="org.apache.lenya.modules.lucene.impl.MetaDataFieldRegistryImpl"/>
+
+</xconf>
Added: lenya/trunk/src/modules/lucene/config/cocoon-xconf/queryString-module.xconf
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/config/cocoon-xconf/queryString-module.xconf?rev=640893&view=auto
==============================================================================
--- lenya/trunk/src/modules/lucene/config/cocoon-xconf/queryString-module.xconf (added)
+++ lenya/trunk/src/modules/lucene/config/cocoon-xconf/queryString-module.xconf Tue Mar 25 09:48:47 2008
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- $Id: doctypes.xconf 164635 2005-04-25 20:01:43Z tschlabach $ -->
+
+<xconf xpath="/cocoon/input-modules" unless="/cocoon/input-modules/component-instance[@name = 'queryString']">
+
+ <component-instance logger="core.modules.input.queryString" name="queryString"
+ class="org.apache.lenya.modules.lucene.QueryStringModule"/>
+
+</xconf>
Modified: lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/Index.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/Index.java?rev=640893&r1=640892&r2=640893&view=diff
==============================================================================
--- lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/Index.java (original)
+++ lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/Index.java Tue Mar 25 09:48:47 2008
@@ -28,6 +28,7 @@
import org.apache.cocoon.components.search.components.Indexer;
import org.apache.cocoon.components.search.fieldmodel.DateFieldDefinition;
import org.apache.cocoon.components.search.fieldmodel.FieldDefinition;
+import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
@@ -164,7 +165,11 @@
analyzerM = (AnalyzerManager) this.manager
.lookup(AnalyzerManager.ROLE);
- indexer.setAnalyzer(analyzerM.getAnalyzer(getDefaultAnalyzerID()));
+ String analyzerId = getDefaultAnalyzerID();
+ if (analyzerId != null) {
+ Analyzer analyzer = analyzerM.getAnalyzer(analyzerId);
+ indexer.setAnalyzer(analyzer);
+ }
indexer.setIndex(directory);
return indexer;
Modified: lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/AbstractIndexer.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/AbstractIndexer.java?rev=640893&r1=640892&r2=640893&view=diff
==============================================================================
--- lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/AbstractIndexer.java (original)
+++ lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/AbstractIndexer.java Tue Mar 25 09:48:47 2008
@@ -222,12 +222,12 @@
*/
public void optimize() throws IndexException {
// optimize index
- try {
+ //try {
this.switchToADD_MODE(false);
- add_writer.optimize();
- } catch (IOException ex) {
- throw new IndexException("optimization error", ex);
- }
+ //add_writer.optimize();
+ //} catch (IOException ex) {
+ // throw new IndexException("optimization error", ex);
+ //}
}
/*
Modified: lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/DefaultIndexerImpl.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/DefaultIndexerImpl.java?rev=640893&r1=640892&r2=640893&view=diff
==============================================================================
--- lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/DefaultIndexerImpl.java (original)
+++ lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/DefaultIndexerImpl.java Tue Mar 25 09:48:47 2008
@@ -90,7 +90,7 @@
flushBufferedDocs();
}
bufferSize = defaultMaxBufDocs;
- this.optimize();
+ //this.optimize();
super.release();
}
Modified: lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/IndexManagerImpl.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/IndexManagerImpl.java?rev=640893&r1=640892&r2=640893&view=diff
==============================================================================
--- lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/IndexManagerImpl.java (original)
+++ lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/components/search/components/impl/IndexManagerImpl.java Tue Mar 25 09:48:47 2008
@@ -43,11 +43,16 @@
import org.apache.excalibur.source.SourceResolver;
import org.apache.excalibur.source.SourceUtil;
import org.apache.lenya.cms.cocoon.components.context.ContextUtility;
+import org.apache.lenya.cms.metadata.Element;
+import org.apache.lenya.cms.metadata.ElementSet;
+import org.apache.lenya.cms.metadata.MetaDataException;
+import org.apache.lenya.cms.metadata.MetaDataRegistry;
import org.apache.lenya.cms.publication.DocumentFactory;
import org.apache.lenya.cms.publication.DocumentUtil;
import org.apache.lenya.cms.publication.Publication;
import org.apache.lenya.cms.publication.PublicationException;
import org.apache.lenya.cms.publication.PublicationManager;
+import org.apache.lenya.modules.lucene.MetaDataFieldRegistry;
/**
* Index Manager Component. Configure and Manage the differents indexes.
@@ -106,7 +111,8 @@
/**
* type of the field: "text, "keyword", "date" (see
*
- * @see org.apache.cocoon.components.search.fieldmodel.FieldDefinition class)
+ * @see org.apache.cocoon.components.search.fieldmodel.FieldDefinition
+ * class)
*/
public static final String TYPE_ATTRIBUTE = "type";
@@ -126,8 +132,8 @@
public static final String INDEX_CONF_FILE = "search/lucene_index.xml";
/**
- * check the config file each time the getIndex is called to update if necessary the
- * configuration
+ * check the config file each time the getIndex is called to update if
+ * necessary the configuration
*/
// public static final String CHECK_ATTRIBUTE = "check";
/**
@@ -135,7 +141,8 @@
*/
// public static final String CONFIG_ATTRIBUTE = "config";
/**
- * Check or not the configuration file (automatic update if the file is changed)
+ * Check or not the configuration file (automatic update if the file is
+ * changed)
*/
// private boolean check;
/**
@@ -147,7 +154,7 @@
private Map indexMap;
protected Map indexes() {
- if(this.indexMap == null) {
+ if (this.indexMap == null) {
this.indexMap = new HashMap();
loadIndexes();
}
@@ -259,8 +266,8 @@
* @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
*/
public void configure(Configuration configuration) throws ConfigurationException {
- this.indexerRole = configuration.getChild(INDEXER_ELEMENT)
- .getAttribute(INDEXER_ROLE_ATTRIBUTE);
+ this.indexerRole = configuration.getChild(INDEXER_ELEMENT).getAttribute(
+ INDEXER_ROLE_ATTRIBUTE);
}
/**
@@ -283,6 +290,8 @@
*/
private void addIndexes(Configuration configuration) throws ConfigurationException {
AnalyzerManager analyzerManager = null;
+ MetaDataFieldRegistry registry = null;
+
Configuration[] confs = configuration.getChildren(INDEX_ELEMENT);
if (confs.length == 0) {
@@ -290,20 +299,33 @@
}
try {
analyzerManager = (AnalyzerManager) this.manager.lookup(AnalyzerManager.ROLE);
+ registry = (MetaDataFieldRegistry) this.manager.lookup(MetaDataFieldRegistry.ROLE);
// configure each index
for (int i = 0; i < confs.length; i++) {
String id = confs[i].getAttribute(ID_ATTRIBUTE);
- String analyzerid = confs[i].getAttribute(INDEX_DEFAULTANALZER_ATTRIBUTE);
- String directory = confs[i].getAttribute(INDEX_DIRECTORY_ATTRIBUTE);
- if (!analyzerManager.exist(analyzerid)) {
+ String analyzerid = confs[i].getAttribute(INDEX_DEFAULTANALZER_ATTRIBUTE, null);
+ if (analyzerid != null && !analyzerManager.exist(analyzerid)) {
throw new ConfigurationException("Analyzer " + analyzerid + " no found");
}
- Configuration[] fields = confs[i].getChild(STRUCTURE_ELEMENT)
- .getChildren(FIELD_ELEMENT);
+ String directory = confs[i].getAttribute(INDEX_DIRECTORY_ATTRIBUTE);
+
+ Configuration[] fields = confs[i].getChild(STRUCTURE_ELEMENT).getChildren(
+ FIELD_ELEMENT);
IndexStructure docdecl = new IndexStructure();
+
+ addMetaDataFieldDefinitions(registry, docdecl);
+
+ FieldDefinition uuidDef = FieldDefinition.create("uuid", FieldDefinition.KEYWORD);
+ uuidDef.setStore(true);
+ docdecl.addFieldDef(uuidDef);
+
+ FieldDefinition langDef = FieldDefinition.create("language", FieldDefinition.KEYWORD);
+ langDef.setStore(true);
+ docdecl.addFieldDef(langDef);
+
for (int j = 0; j < fields.length; j++) {
FieldDefinition fielddecl;
@@ -332,7 +354,8 @@
// field dateformat attribute
if (fielddecl.getType() == FieldDefinition.DATE) {
String dateformat_field = fields[j].getAttribute(DATEFORMAT_ATTRIBUTE);
- ((DateFieldDefinition) fielddecl).setDateFormat(new SimpleDateFormat(dateformat_field));
+ ((DateFieldDefinition) fielddecl).setDateFormat(new SimpleDateFormat(
+ dateformat_field));
}
this.getLogger().debug("field added: " + fielddecl);
@@ -351,7 +374,9 @@
if (index.setDirectory(directory)) {
this.getLogger().warn("directory " + directory + " was locked ");
}
- index.setDefaultAnalyzerID(analyzerid);
+ if (analyzerid != null) {
+ index.setDefaultAnalyzerID(analyzerid);
+ }
index.setStructure(docdecl);
index.setManager(manager);
@@ -367,7 +392,24 @@
if (analyzerManager != null) {
this.manager.release(analyzerManager);
}
+ if (registry != null) {
+ this.manager.release(registry);
+ }
+ }
+ }
+
+ protected void addMetaDataFieldDefinitions(MetaDataFieldRegistry registry,
+ IndexStructure indexStructure) throws MetaDataException {
+ String[] fieldNames = registry.getFieldNames();
+ for (int i = 0; i < fieldNames.length; i++) {
+ FieldDefinition fieldDef = FieldDefinition.create(fieldNames[i], FieldDefinition.TEXT);
+ fieldDef.setStore(false);
+ indexStructure.addFieldDef(fieldDef);
}
+ }
+
+ public static String getUniversalName(String namespace, String elementName) {
+ return "{" + namespace + "}" + elementName;
}
/**
Modified: lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/transformation/LuceneIndexTransformer2.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/transformation/LuceneIndexTransformer2.java?rev=640893&r1=640892&r2=640893&view=diff
==============================================================================
--- lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/transformation/LuceneIndexTransformer2.java (original)
+++ lenya/trunk/src/modules/lucene/java/src/org/apache/cocoon/transformation/LuceneIndexTransformer2.java Tue Mar 25 09:48:47 2008
@@ -17,6 +17,9 @@
package org.apache.cocoon.transformation;
import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.Map;
import org.apache.avalon.excalibur.pool.Recyclable;
@@ -42,6 +45,7 @@
import org.apache.lenya.ac.UserManager;
import org.apache.lenya.cms.repository.RepositoryUtil;
import org.apache.lenya.cms.repository.Session;
+import org.apache.lenya.modules.lucene.MetaDataFieldRegistry;
import org.apache.lenya.notification.Message;
import org.apache.lenya.notification.NotificationUtil;
import org.apache.lucene.analysis.Analyzer;
@@ -208,6 +212,8 @@
public static final int DELETING_PROCESS = 6;
+ protected static final String NAMESPACE_ATTRIBUTE = "namespace";
+
// Runtime variables
private int mergeFactor;
@@ -236,6 +242,8 @@
private String uuid;
private String language;
+ private MetaDataFieldRegistry registry;
+
/**
* Setup the transformer.
*/
@@ -356,11 +364,13 @@
case IN_DOCUMENT_PROCESS:
if (LUCENE_FIELD_ELEMENT.equals(localName)) {
-
+ final String namespace = atts.getValue(NAMESPACE_ATTRIBUTE);
+ final String name = atts.getValue(LUCENE_FIELD_NAME_ATTRIBUTE);
+
// set the field name
- this.fieldname = atts.getValue(LUCENE_FIELD_NAME_ATTRIBUTE);
+ this.fieldname = namespace == null ? name : getMetaDataFieldName(namespace, name);
if (this.fieldname == null || this.fieldname.equals("")) {
- handleError("<lucene:field> element must contain name attribut");
+ handleError("<lucene:field> element must contain name attribute");
}
// clear the text buffer
@@ -385,6 +395,17 @@
}
}
+ protected String getMetaDataFieldName(String namespace, String elementName) {
+ if (this.registry == null) {
+ try {
+ this.registry = (MetaDataFieldRegistry) this.manager.lookup(MetaDataFieldRegistry.ROLE);
+ } catch (ServiceException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return this.registry.getFieldName(namespace, elementName);
+ }
+
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
// getLogger().debug("END processing: "+processing+" "+localName);
@@ -399,7 +420,7 @@
this.processing = NO_PROCESSING;
super.endElement(namespaceURI, localName, qName);
} else {
- handleError("</lucene:" + LUCENE_DELETING_ELEMENT + " was expected!");
+ handleUnexpectedClosingElement(localName, LUCENE_DELETING_ELEMENT);
}
break;
@@ -410,7 +431,7 @@
this.processing = NO_PROCESSING;
super.endElement(namespaceURI, localName, qName);
} else {
- handleError("</lucene:" + LUCENE_DELETING_ELEMENT + " was expected!");
+ handleUnexpectedClosingElement(localName, LUCENE_DELETING_ELEMENT);
}
break;
@@ -434,7 +455,7 @@
super.endElement(namespaceURI, localName, qName);
this.processing = INDEX_PROCESS;
} else {
- handleError("</lucene:" + LUCENE_DOCUMENT_ELEMENT + " was expected!");
+ handleUnexpectedClosingElement(localName, LUCENE_DOCUMENT_ELEMENT);
}
break;
@@ -454,7 +475,7 @@
super.endElement(namespaceURI, localName, qName);
this.processing = DELETE_PROCESS;
} else {
- handleError("</lucene:" + LUCENE_DOCUMENT_ELEMENT + " was expected!");
+ handleUnexpectedClosingElement(localName, LUCENE_DOCUMENT_ELEMENT);
}
break;
@@ -462,30 +483,34 @@
if (LUCENE_FIELD_ELEMENT.equals(localName)) {
// create lucene field
- Field f = null;
try {
- f = index.createField(fieldname, fieldvalue.toString());
+ Field f = index.createField(fieldname, fieldvalue.toString());
+ f.setBoost(fieldboost);
+
+ // add field to the lucene document
+ bodyDocument.add(f);
+ processing = IN_DOCUMENT_PROCESS;
} catch (IndexException ex) {
handleError(ex);
}
- f.setBoost(fieldboost);
-
- // add field to the lucene document
- bodyDocument.add(f);
- processing = IN_DOCUMENT_PROCESS;
} else {
- handleError("</lucene:" + LUCENE_FIELD_ELEMENT + " was expected!");
+ handleUnexpectedClosingElement(localName, LUCENE_FIELD_ELEMENT);
}
break;
default:
- handleError("unknow element '" + LUCENE_FIELD_ELEMENT + "'!");
+ handleError("Inappropriate element '" + localName + "' in state '" + processing + "'!");
}
} else {
super.endElement(namespaceURI, localName, qName);
}
}
+ protected void handleUnexpectedClosingElement(String localName, String expectedLocalName)
+ throws SAXException {
+ handleError("</lucene:" + expectedLocalName + "> was expected instead of </lucene:" + localName + ">!");
+ }
+
protected boolean canIndex() {
return this.indexer != null;
}
@@ -510,48 +535,18 @@
*/
private void initIndexer(Attributes atts) throws SAXException {
- String id = atts.getValue(LUCENE_INDEXING_INDEXID_ATTRIBUTE);
- String analyzerid = atts.getValue(LUCENE_URI, LUCENE_INDEXING_ANALYZER_ATTRIBUTE);
- String mergeF = atts.getValue(LUCENE_URI, LUCENE_INDEXING_MERGE_FACTOR_ATTRIBUTE);
- String clear = atts.getValue(LUCENE_URI, LUCENE_INDEXING_CREATE_ATTRIBUTE);
+ final String indexId = atts.getValue(LUCENE_INDEXING_INDEXID_ATTRIBUTE);
+ final String mergeF = atts.getValue(LUCENE_URI, LUCENE_INDEXING_MERGE_FACTOR_ATTRIBUTE);
+ final String clear = atts.getValue(LUCENE_URI, LUCENE_INDEXING_CREATE_ATTRIBUTE);
attrs = new AttributesImpl(atts);
- // set the indexer
- try {
- IndexManager indexM = (IndexManager) manager.lookup(IndexManager.ROLE);
- index = indexM.getIndex(id);
- if (index == null) {
- handleError("index [" + id + "] no found in the index definition");
- }
- indexer = index.getIndexer();
- manager.release(indexM);
- } catch (ServiceException ex1) {
- handleError(ex1);
-
- } catch (IndexException ex3) {
- handleError("get Indexer error for index [" + id + "]", ex3);
- }
-
- // set a custum analyzer (default: the analyzer of the index)
- if (analyzerid != null) {
- Analyzer analyzer = null;
- try {
- AnalyzerManager analyzerM = (AnalyzerManager) manager.lookup(AnalyzerManager.ROLE);
- analyzer = analyzerM.getAnalyzer(analyzerid);
- indexer.setAnalyzer(analyzer);
- manager.release(analyzerM);
- } catch (ServiceException ex1) {
- handleError(ex1);
- } catch (ConfigurationException ex2) {
- handleError("error setting analyzer for index [" + id + "]", ex2);
- }
- } else {
-
- attrs.addAttribute(LUCENE_URI, LUCENE_INDEXING_ANALYZER_ATTRIBUTE,
- LUCENE_INDEXING_ANALYZER_ATTRIBUTE, "CDATA", index.getDefaultAnalyzerID());
- }
+ setIndexer(indexId);
if (canIndex()) {
+
+ String analyzerId = atts.getValue(LUCENE_URI, LUCENE_INDEXING_ANALYZER_ATTRIBUTE);
+ setAnalyzer(analyzerId);
+
// set clear mode
boolean new_index = (clear != null && clear.toLowerCase().equals("true")) ? true
: false;
@@ -571,11 +566,61 @@
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug(
- "index " + id + " clear: " + new_index + " analyzerid: " + analyzerid
+ "index " + indexId + " clear: " + new_index + " analyzerid: " + analyzerId
+ "mergefactor: " + mergeF);
}
}
}
+
+ protected void setIndexer(String indexId) throws SAXException {
+ IndexManager indexManager = null;
+ try {
+ indexManager = (IndexManager) manager.lookup(IndexManager.ROLE);
+ index = indexManager.getIndex(indexId);
+ if (index == null) {
+ handleError("index [" + indexId + "] no found in the index definition");
+ }
+ else {
+ indexer = index.getIndexer();
+ if (indexer == null) {
+ handleError("Index [" + indexId + "] did return a null indexer.");
+ }
+ }
+ } catch (ServiceException ex1) {
+ handleError(ex1);
+ } catch (IndexException ex3) {
+ handleError("get Indexer error for index [" + indexId + "]", ex3);
+ } finally {
+ manager.release(indexManager);
+ }
+ }
+
+ /**
+ * Set a custum analyzer (default: the analyzer of the index).
+ * @param analyzerId The analyzer ID (may be null)
+ * @throws SAXException if an error occurs.
+ */
+ protected void setAnalyzer(String analyzerId) throws SAXException {
+ if (analyzerId == null) {
+ analyzerId = index.getDefaultAnalyzerID();
+ }
+ if (analyzerId != null) {
+ Analyzer analyzer = null;
+ AnalyzerManager analyzerManager = null;
+ try {
+ analyzerManager = (AnalyzerManager) manager.lookup(AnalyzerManager.ROLE);
+ analyzer = analyzerManager.getAnalyzer(analyzerId);
+ indexer.setAnalyzer(analyzer);
+ } catch (ServiceException ex1) {
+ handleError(ex1);
+ } catch (ConfigurationException ex2) {
+ handleError("error setting analyzer for index [" + this.index.getID() + "]", ex2);
+ }
+ finally {
+ manager.release(analyzerManager);
+ }
+ }
+ }
void handleError(String message, Exception ex) throws SAXException {
handleError(message + ": " + getExceptionMessage(ex));
@@ -588,7 +633,10 @@
protected String getExceptionMessage(Exception ex) throws SAXException {
String exMsg = ex.getMessage();
String msg = exMsg == null ? "" : " (" + exMsg + ")";
- return ex.getClass().getName() + msg;
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(stringWriter);
+ ex.printStackTrace(printWriter);
+ return ex.getClass().getName() + msg + ", Stack trace: " + stringWriter.toString();
}
/**
Added: lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/MetaDataFieldRegistry.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/MetaDataFieldRegistry.java?rev=640893&view=auto
==============================================================================
--- lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/MetaDataFieldRegistry.java (added)
+++ lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/MetaDataFieldRegistry.java Tue Mar 25 09:48:47 2008
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lenya.modules.lucene;
+
+/**
+ * Map meta data elements to Lucene index fields.
+ */
+public interface MetaDataFieldRegistry {
+
+ /**
+ * The Avalon service role.
+ */
+ String ROLE = MetaDataFieldRegistry.class.getName();
+
+ /**
+ * @param namespace The namespace URI of the meta data element set.
+ * @param elementName The name of the meta data element.
+ * @return The name of the corresponding Lucene index field.
+ */
+ String getFieldName(String namespace, String elementName);
+
+ /**
+ * @return All field names.
+ */
+ String[] getFieldNames();
+
+}
Added: lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/QueryStringModule.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/QueryStringModule.java?rev=640893&view=auto
==============================================================================
--- lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/QueryStringModule.java (added)
+++ lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/QueryStringModule.java Tue Mar 25 09:48:47 2008
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lenya.modules.lucene;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Map;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.cocoon.components.modules.input.AbstractInputModule;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.lenya.cms.metadata.Element;
+import org.apache.lenya.cms.metadata.ElementSet;
+import org.apache.lenya.cms.metadata.MetaDataRegistry;
+
+/**
+ * Creates a Lucene query string from a <em>queryString</em> request parameter
+ * which can be passed to the search generator.
+ */
+public class QueryStringModule extends AbstractInputModule implements Serviceable {
+
+ protected static final String PARAM_QUERY_STRING = "queryString";
+ protected static final String[] DEFAULT_FIELDS = { "body" };
+
+ protected static final char[] ESCAPED_CHARACTERS = { '+', '-', '&', '|', '!', '(', ')', '{',
+ '}', '[', ']', '^', '"', '~', '*', '?', ':', '\\' };
+
+ private ServiceManager manager;
+
+ public Object getAttribute(String name, Configuration modeConf, Map objectModel)
+ throws ConfigurationException {
+
+ if (name.equals("queryString")) {
+ return getQueryString(objectModel);
+ } else {
+ throw new IllegalArgumentException("The attribute [" + name + "] is not supported.");
+ }
+
+ }
+
+ protected String getQueryString(Map objectModel) {
+ Request request = ObjectModelHelper.getRequest(objectModel);
+ String searchTerm = request.getParameter(PARAM_QUERY_STRING);
+
+ if (searchTerm == null || searchTerm.trim().equals("")) {
+ return "";
+ }
+
+ StringBuffer queryString = new StringBuffer();
+
+ for (int i = 0; i < DEFAULT_FIELDS.length; i++) {
+ appendTerm(queryString, DEFAULT_FIELDS[i], searchTerm);
+ }
+
+ MetaDataRegistry registry = null;
+ MetaDataFieldRegistry fieldRegistry = null;
+ try {
+ registry = (MetaDataRegistry) this.manager.lookup(MetaDataRegistry.ROLE);
+ fieldRegistry = (MetaDataFieldRegistry) this.manager.lookup(MetaDataFieldRegistry.ROLE);
+ String[] namespaces = registry.getNamespaceUris();
+ for (int n = 0; n < namespaces.length; n++) {
+ ElementSet elementSet = registry.getElementSet(namespaces[n]);
+ Element[] elements = elementSet.getElements();
+ for (int e = 0; e < elements.length; e++) {
+ if (elements[e].isSearchable()) {
+ String field = fieldRegistry.getFieldName(namespaces[n], elements[e].getName());
+ appendTerm(queryString, field, searchTerm);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (registry != null) {
+ this.manager.release(registry);
+ }
+ if (fieldRegistry != null) {
+ this.manager.release(fieldRegistry);
+ }
+ }
+ return queryString.toString();
+ }
+
+ protected boolean shallEscape(char c) {
+ for (int i = 0; i < ESCAPED_CHARACTERS.length; i++) {
+ if (ESCAPED_CHARACTERS[i] == c) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected String escape(final String prefix) {
+ StringBuilder builder = new StringBuilder();
+ StringCharacterIterator i = new StringCharacterIterator(prefix);
+ char c = i.current();
+ while (c != CharacterIterator.DONE) {
+ if (shallEscape(c)) {
+ builder.append('\\');
+ }
+ builder.append(c);
+ c = i.next();
+ }
+ return builder.toString();
+ }
+
+ protected void appendTerm(StringBuffer queryString, String field, String searchTerm) {
+ if (queryString.length() > 0) {
+ queryString.append(" OR ");
+ }
+ String term = getTerm(field, searchTerm);
+ queryString.append(term);
+ }
+
+ protected String getTerm(String field, String searchTerm) {
+ return escape(field) + ":" + searchTerm;
+ }
+
+ public void service(ServiceManager manager) throws ServiceException {
+ this.manager = manager;
+ }
+
+}
Added: lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/impl/MetaDataFieldRegistryImpl.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/impl/MetaDataFieldRegistryImpl.java?rev=640893&view=auto
==============================================================================
--- lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/impl/MetaDataFieldRegistryImpl.java (added)
+++ lenya/trunk/src/modules/lucene/java/src/org/apache/lenya/modules/lucene/impl/MetaDataFieldRegistryImpl.java Tue Mar 25 09:48:47 2008
@@ -0,0 +1,102 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.lenya.modules.lucene.impl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.lenya.cms.metadata.Element;
+import org.apache.lenya.cms.metadata.ElementSet;
+import org.apache.lenya.cms.metadata.MetaDataRegistry;
+import org.apache.lenya.modules.lucene.MetaDataFieldRegistry;
+import org.apache.lenya.util.Assert;
+
+public class MetaDataFieldRegistryImpl extends AbstractLogEnabled implements MetaDataFieldRegistry,
+ ThreadSafe, Serviceable {
+
+ private MetaDataRegistry registry;
+ private ServiceManager manager;
+ private Map namespace2prefix;
+
+ public String getFieldName(String namespace, String elementName) {
+ Assert.notNull("namespace", namespace);
+ Assert.notNull("element name", elementName);
+ initPrefixes();
+ Assert.isTrue("namespace [" + namespace + "] exists", this.namespace2prefix
+ .containsKey(namespace));
+ String prefix = (String) this.namespace2prefix.get(namespace);
+ return prefix + elementName;
+ }
+
+ protected MetaDataRegistry getRegistry() {
+ if (this.registry == null) {
+ try {
+ this.registry = (MetaDataRegistry) this.manager.lookup(MetaDataRegistry.ROLE);
+ } catch (ServiceException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return this.registry;
+ }
+
+ protected void initPrefixes() {
+ if (this.namespace2prefix == null) {
+ this.namespace2prefix = new HashMap();
+ MetaDataRegistry registry = getRegistry();
+ try {
+ String[] namespaces = registry.getNamespaceUris();
+ for (int n = 0; n < namespaces.length; n++) {
+ String prefix = "{" + namespaces[n] + "}";
+ this.namespace2prefix.put(namespaces[n], prefix);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ public void service(ServiceManager manager) throws ServiceException {
+ this.manager = manager;
+ }
+
+ public String[] getFieldNames() {
+ MetaDataRegistry registry = getRegistry();
+ Set fieldNames = new HashSet();
+ try {
+ String[] namespaces = registry.getNamespaceUris();
+ for (int n = 0; n < namespaces.length; n++) {
+ ElementSet elementSet = registry.getElementSet(namespaces[n]);
+ Element[] elements = elementSet.getElements();
+ for (int e = 0; e < elements.length; e++) {
+ String fieldName = getFieldName(namespaces[n], elements[e].getName());
+ fieldNames.add(fieldName);
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return (String[]) fieldNames.toArray(new String[fieldNames.size()]);
+ }
+
+}
Modified: lenya/trunk/src/modules/lucene/sitemap.xmap
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/sitemap.xmap?rev=640893&r1=640892&r2=640893&view=diff
==============================================================================
--- lenya/trunk/src/modules/lucene/sitemap.xmap (original)
+++ lenya/trunk/src/modules/lucene/sitemap.xmap Tue Mar 25 09:48:47 2008
@@ -93,36 +93,15 @@
<!-- {1:pub}/{2:area}/{3:queryString} -->
<map:match pattern="search-generator/*/*/*">
- <map:select type="parameter">
- <map:parameter name="parameter-selector-test" value="{3}"/>
- <map:when test="">
- <map:generate type="search">
- <map:parameter name="index" value="{index-path:{1}-{2}}"/>
- <map:parameter name="query" value=""/>
- </map:generate>
- </map:when>
- <map:otherwise>
- <map:generate type="search">
- <map:parameter name="index" value="{index-path:{1}-{2}}"/>
- <map:parameter name="query" value="title:{3} OR description:{3} OR subject:{3} OR body:{3}"/>
- </map:generate>
- </map:otherwise>
- </map:select>
+ <map:generate type="search">
+ <map:parameter name="index" value="{index-path:{1}-{2}}"/>
+ <map:parameter name="query" value="{queryString:queryString}"/>
+ </map:generate>
<map:serialize type="xml"/>
</map:match>
- <!-- {1:pub}/{2:area} -->
- <map:match pattern="search/*/*.xml">
- <map:generate src="cocoon:/search-generator/{1}/{2}/{request-param:queryString}"/>
- <map:transform type="uuid2url">
- <map:parameter name="pubId" value="{1}"/>
- <map:parameter name="area" value="{2}"/>
- </map:transform>
- <map:serialize type="xml"/>
- </map:match>
-
<map:match pattern="search.xml">
- <map:generate src="cocoon:/search/{page-envelope:publication-id}/{page-envelope:area}.xml"/>
+ <map:generate src="cocoon:/search-generator/{page-envelope:publication-id}/{page-envelope:area}/{request-param:queryString}"/>
<map:transform src="fallback://lenya/modules/lucene/xslt/search2html.xsl">
<map:parameter name="url" value="{page-envelope:document-url}"/>
<map:parameter name="area" value="{page-envelope:area}"/>
@@ -131,14 +110,28 @@
<map:parameter name="use-request-parameters" value="true"/>
<map:parameter name="queryString" value="{request-param:queryString}"/>
</map:transform>
+ <map:transform type="metaData">
+ <map:parameter name="pubid" value="{page-envelope:publication-id}"/>
+ <map:parameter name="area" value="{page-envelope:area}"/>
+ </map:transform>
<map:transform type="cinclude"/>
<map:transform type="uuid2url"/>
<map:serialize type="xml"/>
</map:match>
+
+ <!-- index/{1:pub-id}/{2:area}/{3:uuid}/{4:language} -->
+ <map:match pattern="index-metadata/*/*/*/*">
+ <map:generate src="cocoon://modules/metadata/{1}/{2}/{3}/{4}"/>
+ <map:transform src="fallback://lenya/modules/lucene/xslt/metadata2index.xsl"/>
+ <map:serialize type="xml"/>
+ </map:match>
- <!-- {pub-id}/{area}/{uuid}/{language} -->
+ <!-- {1:pub-id}/{2:area}/{3:uuid}/{4:language} -->
<map:match pattern="index-document/*/*/*/*">
- <map:generate src="{resource-type:{doc-info:{1}:{2}:{3}:{4}:resourceType}:format-luceneIndex}/{1}/{2}/{3}/{4}"/>
+ <map:aggregate element="index" ns="http://apache.org/cocoon/lucene/1.0">
+ <map:part src="lenya-document:{3},pub={1},area={2},lang={4}?format=luceneIndex" strip-root="true"/>
+ <map:part src="cocoon:/index-metadata/{1}/{2}/{3}/{4}"/>
+ </map:aggregate>
<map:transform src="fallback://lenya/modules/lucene/xslt/index.xsl">
<map:parameter name="index" value="{1}-{2}"/>
<map:parameter name="uuid" value="{3}"/>
Modified: lenya/trunk/src/modules/lucene/xslt/index.xsl
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/xslt/index.xsl?rev=640893&r1=640892&r2=640893&view=diff
==============================================================================
--- lenya/trunk/src/modules/lucene/xslt/index.xsl (original)
+++ lenya/trunk/src/modules/lucene/xslt/index.xsl Tue Mar 25 09:48:47 2008
@@ -14,6 +14,8 @@
<xsl:template match="/lucene:index">
<lucene:index indexid="{$index}" lucene:clear="false" lucene:merge-factor="100" lucene:analyzer="stopword_{$language}">
<lucene:document uid="{$uuid}:{$language}">
+ <lucene:field name="uuid"><xsl:value-of select="$uuid"/></lucene:field>
+ <lucene:field name="language"><xsl:value-of select="$language"/></lucene:field>
<xsl:apply-templates select="lucene:document/*"/>
</lucene:document>
</lucene:index>
Added: lenya/trunk/src/modules/lucene/xslt/metadata2index.xsl
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/xslt/metadata2index.xsl?rev=640893&view=auto
==============================================================================
--- lenya/trunk/src/modules/lucene/xslt/metadata2index.xsl (added)
+++ lenya/trunk/src/modules/lucene/xslt/metadata2index.xsl Tue Mar 25 09:48:47 2008
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:lucene="http://apache.org/cocoon/lucene/1.0"
+ xmlns:meta="http://apache.org/cocoon/lenya/metadata/1.0"
+ >
+
+ <xsl:template match="meta:metadata">
+ <lucene:document>
+ <xsl:apply-templates select="*/*"/>
+ </lucene:document>
+ </xsl:template>
+
+
+ <xsl:template match="*">
+ <lucene:field boost="0.5" namespace="{namespace-uri()}" name="{local-name()}"><xsl:value-of select="."/></lucene:field>
+ </xsl:template>
+
+
+</xsl:stylesheet>
Modified: lenya/trunk/src/modules/lucene/xslt/search2html.xsl
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/lucene/xslt/search2html.xsl?rev=640893&r1=640892&r2=640893&view=diff
==============================================================================
--- lenya/trunk/src/modules/lucene/xslt/search2html.xsl (original)
+++ lenya/trunk/src/modules/lucene/xslt/search2html.xsl Tue Mar 25 09:48:47 2008
@@ -23,6 +23,7 @@
xmlns="http://www.w3.org/1999/xhtml"
xmlns:cinclude="http://apache.org/cocoon/include/1.0"
xmlns:i18n="http://apache.org/cocoon/i18n/2.1"
+ xmlns:meta="http://apache.org/lenya/meta/1.0/"
exclude-result-prefixes="cinclude search xhtml"
>
@@ -123,27 +124,18 @@
<xsl:template match="search:hit">
<li class="search-result">
<div class="search-result-rank"><xsl:value-of select="@rank + 1"/>. </div>
+ <xsl:variable name="uuid" select="search:field[@name='uuid']"/>
+ <xsl:variable name="language" select="search:field[@name='language']"/>
<div class="search-result-title">
- <xsl:variable name="titleField" select="search:field[attribute::name='title']"/>
- <xsl:variable name="title">
- <xsl:choose>
- <xsl:when test="normalize-space($titleField) != ''">
- <xsl:value-of select="$titleField"/>
- </xsl:when>
- <xsl:otherwise><i18n:text>No Title</i18n:text></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:choose>
- <xsl:when test="normalize-space(search:field[@name = 'uid']) != ''">
- <a href="{$root}{search:field[attribute::name='uid']}"><xsl:value-of select="$title"/></a>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$title"/> (<i18n:text>not in site structure</i18n:text>)
- </xsl:otherwise>
- </xsl:choose>
- <span class="search-result-score"> (<i18n:text>Score</i18n:text>: <xsl:value-of select="format-number( @score, '### %' )"/>)</span>
+ <a href="lenya-document:{$uuid},lang={$language}">
+ <meta:value element="title" ns="http://purl.org/dc/elements/1.1/" default="No Title"
+ i18n:attr="default" uuid="{$uuid}" lang="{$language}"/>
+ </a>
+ <span class="search-result-score"> (<i18n:text>Score</i18n:text>: <xsl:value-of select="format-number( @score, '### %' )"/>)</span>
+ </div>
+ <div class="search-result-description">
+ <meta:value element="description" ns="http://purl.org/dc/elements/1.1/" default="" uuid="{$uuid}" lang="{$language}"/>
</div>
- <div class="search-result-description"><xsl:value-of select="search:field[attribute::name='description']"/></div>
</li>
</xsl:template>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@lenya.apache.org
For additional commands, e-mail: commits-help@lenya.apache.org