Author: ivol37 at gmail.com
Date: Fri Jan 28 17:24:50 2011
New Revision: 716

Log:


Added:
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/RestHttpProxy.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/RestHttpResponse.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrErrorBean.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrIndexBean.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrTenantIndicesBean.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/RestHttpProxyImpl.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrConfiguration.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrConfigurationImpl.java
   sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/protwords.txt
   sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/schema.xml
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/solrconfig.xml
   sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/stopwords.txt
   sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/synonyms.txt
Removed:
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/default_schema.xml
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/default_solrconfig.xml
Modified:
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/SolrApi.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrApiImpl.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrDaemonServiceImpl.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrRestServiceImpl.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrTest.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrUtil.java
   
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/osgi/Activator.java

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/RestHttpProxy.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/RestHttpProxy.java
     Fri Jan 28 17:24:50 2011
@@ -0,0 +1,35 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.searchandindex.solr;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface RestHttpProxy {
+    RestHttpResponse invokeGET(String url) throws IOException;
+
+    RestHttpResponse invokePUT(String url) throws IOException;
+
+    /**
+     * Invoke a PUT request to a REST service and stream content to it.
+     * @param url The URL of the REST service
+     * @param is The InputStream to stream to it
+     * @return The result of the REST service invocation
+     * @throws IOException In case any IO related exception occurred while 
invoking the REST service.
+     */
+    RestHttpResponse streamPUT(String url, InputStream is) throws IOException;
+}

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/RestHttpResponse.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/RestHttpResponse.java
  Fri Jan 28 17:24:50 2011
@@ -0,0 +1,38 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.searchandindex.solr;
+
+public class RestHttpResponse {
+    private int m_statuscode;
+    private String m_body;
+
+    public int getStatuscode() {
+        return m_statuscode;
+    }
+
+    public void setStatuscode(int statuscode) {
+        m_statuscode = statuscode;
+    }
+
+    public String getBody() {
+        return m_body;
+    }
+
+    public void setBody(String body) {
+        m_body = body;
+    }
+}

Modified: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/SolrApi.java
==============================================================================
--- 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/SolrApi.java
   (original)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/SolrApi.java
   Fri Jan 28 17:24:50 2011
@@ -32,7 +32,7 @@
 
     QueryResponse queryIndex(Tenant tenant, String index, String query) throws 
SolrServerException;
 
-    Collection<String> getIndices(Tenant tenant) throws SolrServerException;
+    Collection<String> getCores(Tenant tenant) throws SolrServerException;
 
     String getSchema(Tenant tenant, String index) throws IOException;
 }

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrErrorBean.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrErrorBean.java
        Fri Jan 28 17:24:50 2011
@@ -0,0 +1,29 @@
+package org.amdatu.searchandindex.solr.bean;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+ at SuppressWarnings("restriction")
+ at XmlRootElement(name = "indices")
+ at XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
+public class SolrErrorBean {
+
+    private String m_errorMessage;
+
+    // Providing a default constructor is required when using JAXB
+    public SolrErrorBean() {
+    }
+
+    public SolrErrorBean(String msg) {
+        m_errorMessage = msg;
+    }
+
+    public String getErrorMessage() {
+        return m_errorMessage;
+    }
+
+    public void setErrorMessage(String msg) {
+        m_errorMessage = msg;
+    }
+}

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrIndexBean.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrIndexBean.java
        Fri Jan 28 17:24:50 2011
@@ -0,0 +1,69 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.searchandindex.solr.bean;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+
+ at SuppressWarnings("restriction")
+ at XmlAccessorType(XmlAccessType.FIELD)
+public class SolrIndexBean {
+    @XmlAttribute(name = "id")
+    private String m_id;
+
+    @XmlElement(name = "corename")
+    private String m_coreName;
+
+    @XmlElement(name = "size")
+    private int m_size;
+
+    // Providing a default constructor is required when using JAXB
+    public SolrIndexBean() {
+    }
+
+    public SolrIndexBean(String id, String coreName, int size) {
+        m_id = id;
+        m_coreName = coreName;
+        m_size = size;
+    }
+
+    public String getId() {
+        return m_id;
+    }
+
+    public void setId(String id) {
+        m_id = id;
+    }
+
+    public String getCoreName() {
+        return m_coreName;
+    }
+
+    public void setCoreName(String coreName) {
+        m_coreName = coreName;
+    }
+
+    public int getSize() {
+        return m_size;
+    }
+
+    public void setSize(int size) {
+        m_size = size;
+    }
+}

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrTenantIndicesBean.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/bean/SolrTenantIndicesBean.java
        Fri Jan 28 17:24:50 2011
@@ -0,0 +1,80 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.searchandindex.solr.bean;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.amdatu.core.tenant.Tenant;
+
+ at SuppressWarnings("restriction")
+ at XmlRootElement(name = "tenant")
+ at XmlAccessorType(XmlAccessType.FIELD)
+/**
+ * Bean that represents a tenant.
+ */
+public class SolrTenantIndicesBean {
+    @XmlAttribute(name = "id")
+    private String m_id;
+
+    @XmlElement(name = "name")
+    private String m_name;
+
+    @XmlElement(name = "index")
+    @XmlElementWrapper(name = "indices")
+    private List<SolrIndexBean> m_indices = new ArrayList<SolrIndexBean>();
+
+    // Providing a default constructor is required when using JAXB
+    public SolrTenantIndicesBean() {
+    }
+
+    public SolrTenantIndicesBean(Tenant tenant) {
+        m_id = tenant.getId();
+        m_name = tenant.getName();
+    }
+
+    public String getId() {
+        return m_id;
+    }
+
+    public void setId(String id) {
+        m_id = id;
+    }
+
+    public String getName() {
+        return m_name;
+    }
+
+    public void setName(String name) {
+        m_name = name;
+    }
+
+    public List<SolrIndexBean> getIndices() {
+        return m_indices;
+    }
+
+    public void setIndices(List<SolrIndexBean> indices) {
+        m_indices = indices;
+    }
+}

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/RestHttpProxyImpl.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/RestHttpProxyImpl.java
    Fri Jan 28 17:24:50 2011
@@ -0,0 +1,91 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.searchandindex.solr.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.amdatu.searchandindex.solr.RestHttpProxy;
+import org.amdatu.searchandindex.solr.RestHttpResponse;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.methods.RequestEntity;
+
+public class RestHttpProxyImpl implements RestHttpProxy {
+
+    public RestHttpResponse invokeGET(String url) throws IOException {
+        return invoke(url, javax.ws.rs.HttpMethod.GET);
+    }
+
+    public RestHttpResponse invokePUT(String url) throws IOException {
+        return invoke(url, javax.ws.rs.HttpMethod.PUT);
+    }
+
+    private RestHttpResponse invoke(String url, String httpMethod) throws 
IOException{
+        HttpClient httpClient = new HttpClient();
+        HttpMethod method = null;
+        if (httpMethod.equals(javax.ws.rs.HttpMethod.GET)) {
+            method = new GetMethod(url);
+        } else if (httpMethod.equals(javax.ws.rs.HttpMethod.PUT)) {
+            method = new PutMethod(url);
+        } else if (httpMethod.equals(javax.ws.rs.HttpMethod.DELETE)) {
+            method = new DeleteMethod(url);
+        } else if (httpMethod.equals(javax.ws.rs.HttpMethod.POST)) {
+            method = new PostMethod(url);
+        }
+        try {
+            // Execute the method, this should return a 200
+            int statusCode = httpClient.executeMethod(method);
+            RestHttpResponse result = new RestHttpResponse();
+            result.setStatuscode(statusCode);
+            if (method.getResponseBody() != null) {
+                result.setBody(new String(method.getResponseBody(), "UTF-8"));
+            }
+            return result;
+        }
+        finally {
+            // Release the connection.
+            method.releaseConnection();
+        }
+    }
+
+
+    public RestHttpResponse streamPUT(String url, InputStream is) throws 
IOException {
+        HttpClient httpClient = new HttpClient();
+        PutMethod method = new PutMethod(url);
+        try {
+            RequestEntity requestEntity = new InputStreamRequestEntity(is);
+            method.setRequestEntity(requestEntity);
+            int statusCode = httpClient.executeMethod(method);
+            RestHttpResponse response = new RestHttpResponse();
+            response.setStatuscode(statusCode);
+            response.setBody(new String(method.getResponseBody(), "UTF-8"));
+            return response;
+        }
+        finally {
+            // Release the connection.
+            method.releaseConnection();
+        }
+    }
+
+
+}

Modified: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrApiImpl.java
==============================================================================
--- 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrApiImpl.java
  (original)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrApiImpl.java
  Fri Jan 28 17:24:50 2011
@@ -20,14 +20,12 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URL;
 import java.util.Collection;
 import java.util.List;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.stream.XMLStreamException;
 
-import org.amdatu.core.config.templates.ConfigTemplateManager;
 import org.amdatu.core.tenant.Tenant;
 import org.amdatu.searchandindex.solr.SolrApi;
 import org.apache.solr.client.solrj.SolrQuery;
@@ -44,41 +42,36 @@
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrResourceLoader;
 import org.apache.solr.schema.IndexSchema;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
 import org.osgi.service.log.LogService;
 import org.xml.sax.SAXException;
 
 @SuppressWarnings("restriction")
 public class SolrApiImpl implements SolrApi {
-    // Statics
-    private static final String DEFAULT_SCHEMA = "conf/default_schema.xml";
-    private static final String DEFAULT_SOLRCONFIG = 
"conf/default_solrconfig.xml";
-
     // Service dependencies injected by the dependency manager
     private volatile LogService m_logService;
-    private volatile BundleContext m_bundleContext;
-    private volatile ConfigTemplateManager m_configTemplateManager;
+    private volatile SolrConfiguration m_solrConfig;
 
     // Private members
-    private File m_workDir;
     private CoreContainer m_coreContainer;
 
-    public SolrApiImpl(File workDir, CoreContainer coreContainer) {
-        m_workDir = workDir;
+    public SolrApiImpl(CoreContainer coreContainer, SolrConfiguration 
solrConfig) {
         m_coreContainer = coreContainer;
+        m_solrConfig = solrConfig;
     }
 
     public void createIndex(Tenant tenant, String index) {
+        createIndex(tenant, index, null);
+    }
+
+    public void createIndex(Tenant tenant, String index, InputStream is) {
         // Verify if a core for this index already exists
-        String coreDirName = tenant.getId() + "/" + index;
         String coreName = tenant.getId() + "_" + index;
         if (m_coreContainer.getCore(coreName) == null) {
             try {
                 m_logService.log(LogService.LOG_INFO, "Creating new Solr index 
'" + index + "' for tenant '" + tenant.getId() + "'");
 
                 // Create a new core. The name of that core will be <tenant 
id>/<index name>
-                createCore(coreName, coreDirName);
+                createCore(tenant.getId(), index, is);
             }
             catch (IOException e) {
                 m_logService.log(LogService.LOG_ERROR, "Could not create Solr 
core configuration for '" + coreName + "'", e);
@@ -92,6 +85,14 @@
         }
     }
 
+    public void deleteIndex(Tenant tenant, String index) {
+        String coreDirName = tenant.getId() + "/" + index;
+        String coreName = tenant.getId() + "_" + index;
+        deleteCore(coreName, coreDirName);
+        m_solrConfig.deleteCore(tenant.getId(), index);
+        m_logService.log(LogService.LOG_DEBUG, "Index '" + coreName + "' 
deleted");
+    }
+
     public void updateIndex(Tenant tenant, String index, InputStream is) 
throws XMLStreamException, SolrServerException, IOException {
         String coreName = tenant.getId() + "_" + index;
         m_logService.log(LogService.LOG_DEBUG, "Starting update for index '" + 
coreName + "'");
@@ -114,12 +115,16 @@
         m_logService.log(LogService.LOG_DEBUG, "Index '" + coreName + "' 
updated");
     }
 
-    public Collection<String> getIndices(Tenant tenant) throws 
SolrServerException {
+    public Collection<String> getCores(Tenant tenant) throws 
SolrServerException {
         return m_coreContainer.getCoreNames();
     }
 
     public QueryResponse queryIndex(Tenant tenant, String index, String query) 
throws SolrServerException {
         String coreName = tenant.getId() + "_" + index;
+        return queryCore(coreName, query);
+    }
+
+    public QueryResponse queryCore(String coreName, String query) throws 
SolrServerException {
         SolrServer server = new EmbeddedSolrServer(m_coreContainer, coreName);
         SolrQuery solrQuery = new SolrQuery();
         solrQuery.setQuery(query);
@@ -127,50 +132,75 @@
     }
 
     public String getSchema(Tenant tenant, String index) throws IOException {
-        File schema = new File(m_workDir, tenant.getId() + "/" + index + 
"/conf/schema.xml");
+        File schema = m_solrConfig.getCoreSchema(tenant.getId(), index);
         String contents = SolrUtil.loadFromFile(schema);
         return contents;
     }
 
-    private void createCore(String coreName, String coreDirName) throws 
IOException, ParserConfigurationException, SAXException {
+    public void setSchema(Tenant tenant, String index, InputStream is) throws 
IOException {
+        deleteIndex(tenant, index);
+        createIndex(tenant, index, is);
+    }
+
+    private void deleteCore(String coreName, String coreDirName) {
         // Save the current context classloader
         final ClassLoader contextClassLoader = 
Thread.currentThread().getContextClassLoader();
         try {
             // Classloader switcheroo
             final ClassLoader classLoader = this.getClass().getClassLoader();
             Thread.currentThread().setContextClassLoader(classLoader);
+            m_coreContainer.remove(coreName);
+            File solr = m_solrConfig.getSolr();
+            m_coreContainer.persistFile(solr);
+        } finally {
+            // Restore classloader
+            Thread.currentThread().setContextClassLoader(contextClassLoader);
+        }
+    }
 
-            // Prepare /conf directory for this core
-            File coreDir = new File(m_workDir, coreDirName);
-            File coreConfDir = new File(m_workDir, coreDirName + "/conf");
-            if (coreConfDir.exists()) {
-                coreConfDir.delete();
-            }
-            coreConfDir.mkdirs();
-            File coresConfigFile = new File(m_workDir, 
SolrDaemonServiceImpl.SOLR);
+    private void createCore(String tenantId, String indexName, InputStream is) 
throws IOException, ParserConfigurationException, SAXException {
+        // Save the current context classloader
+        final ClassLoader contextClassLoader = 
Thread.currentThread().getContextClassLoader();
+        try {
+            // Classloader switcheroo
+            final ClassLoader classLoader = this.getClass().getClassLoader();
+            Thread.currentThread().setContextClassLoader(classLoader);
 
-            Bundle bundle = m_bundleContext.getBundle();
+            // Prepare the configuration files of this new core
+            m_solrConfig.prepareCore(tenantId, indexName, is);
 
-            // Write the schema
-            URL schema = bundle.getResource(DEFAULT_SCHEMA);
-            File targetSchema = new File(m_workDir + "/" + coreDirName + 
"/conf/schema.xml");
-            m_configTemplateManager.writeConfiguration(schema, targetSchema);
-
-            // Write the solrConfig
-            URL solrConfig = bundle.getResource(DEFAULT_SOLRCONFIG);
-            File targetSolrConfig = new File(m_workDir + "/" + coreDirName + 
"/conf/solrconfig.xml");
-            m_configTemplateManager.writeConfiguration(solrConfig, 
targetSolrConfig);
-
-            SolrResourceLoader loader = new 
NakamuraSolrResourceLoader(m_workDir.getAbsolutePath(), classLoader);
-            SolrConfig config = new NakamuraSolrConfig(loader, 
"solrconfig.xml", new FileInputStream(targetSolrConfig));
-            IndexSchema indexSchema = new IndexSchema(config, null, new 
FileInputStream(targetSchema));
+            // Now create the new core
+            String coreName = getCoreName(tenantId, indexName);
+            File coreDir = m_solrConfig.getCoreDirectory(tenantId, indexName);
+            File solrConfig = m_solrConfig.getCoreSolrConfig(tenantId, 
indexName);
+            File schema = m_solrConfig.getCoreSchema(tenantId, indexName);
+            File solr = m_solrConfig.getSolr();
+            File workDir = m_solrConfig.getWorkDirectory();
+
+            SolrResourceLoader loader = new 
NakamuraSolrResourceLoader(workDir.getAbsolutePath(), classLoader);
+            SolrConfig config = new NakamuraSolrConfig(loader, 
"solrconfig.xml", new FileInputStream(solrConfig));
+            IndexSchema indexSchema = new IndexSchema(config, null, new 
FileInputStream(schema));
             CoreDescriptor desc = new CoreDescriptor(m_coreContainer, 
coreName, coreDir.getAbsolutePath());
             SolrCore nakamuraCore = new SolrCore(coreName, 
coreDir.getAbsolutePath(), config, indexSchema, desc);
             m_coreContainer.register(coreName, nakamuraCore, false);
-            m_coreContainer.persistFile(coresConfigFile);
+            m_coreContainer.persistFile(solr);
         } finally {
             // Restore classloader
             Thread.currentThread().setContextClassLoader(contextClassLoader);
         }
     }
+
+    public String getCoreName(Tenant tenant, String index) {
+        return tenant.getId() + "_" + index;
+    }
+
+    public String getCoreName(String tenantId, String index) {
+        return tenantId + "_" + index;
+    }
+
+    public String getIndexName(Tenant tenant, String coreName) {
+        String corePrefix = tenant.getId() + "_";
+        return coreName.substring(corePrefix.length());
+    }
+
 }

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrConfiguration.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrConfiguration.java
    Fri Jan 28 17:24:50 2011
@@ -0,0 +1,72 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.searchandindex.solr.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface SolrConfiguration {
+    File getWorkDirectory();
+
+    /**
+     * Returns the solr.xml file that stores generic Solr configuration (like 
the available cores).
+     * @return The solr.xml file
+     */
+    File getSolr();
+
+    /**
+     * Returns the directory that stores all files related to a particular 
core.
+     * @param tenantId the tenant of the core
+     * @param indexName the index name of the core
+     * @return the directory that stores all files related to a particular 
core.
+     */
+    File getCoreDirectory(String tenantId, String indexName);
+
+    /**
+     * Returns the solr config file of a particular core.
+     * @param tenantId the tenant of the core
+     * @param indexName the index name of the core
+     * @return the solr config file of this core.
+     */
+    File getCoreSolrConfig(String tenantId, String indexName);
+
+    /**
+     * Returns the schema file of a particular core.
+     * @param tenantId the tenant of the core
+     * @param indexName the index name of the core
+     * @return the schema file of this core.
+     */
+    File getCoreSchema(String tenantId, String indexName);
+
+    /**
+     * Initialize generic Solr configuration.
+     * @throws IOException
+     */
+    void initSolr() throws IOException;
+
+    /**
+     * Prepare configuration of a particular core.
+     * @param tenantId
+     * @param indexName
+     * @param schema
+     * @throws IOException
+     */
+    void prepareCore(String tenantId, String indexName, InputStream schema) 
throws IOException;
+
+    void deleteCore(String tenantId, String indexName);
+}

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrConfigurationImpl.java
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrConfigurationImpl.java
        Fri Jan 28 17:24:50 2011
@@ -0,0 +1,214 @@
+/*
+    Copyright (C) 2010 Amdatu.org
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.searchandindex.solr.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.util.Dictionary;
+
+import org.amdatu.core.config.templates.ConfigTemplateManager;
+import org.amdatu.searchandindex.solr.SolrService;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+
+/**
+ * This class is responsible for management of Solr configuration files. The 
default Solr configuation
+ * files are copied to solr/conf upon first startup. Whenever a new core is 
added to Solr, these
+ * configuration files are copied to the new cores. If the configuration files 
are changed in this directory,
+ * new cores will be created with this new configruation.
+ * 
+ * @author ivol
+ */
+public class SolrConfigurationImpl implements SolrConfiguration, 
ManagedService {
+    // Statics
+    private static final String CONF_RESDIR = "conf/";
+    private static final String SOLR = "solr.xml";
+    private static final String SOLR_CONFIG = "solrconfig.xml";
+    private static final String DEFAULT_CONFIG_DIR = "conf";
+    private static final String SCHEMA = "schema.xml";
+    private static final String SYNONYMS = "synonyms.txt";
+    private static final String STOPWORDS = "stopwords.txt";
+    private static final String PROTWORDS = "protwords.txt";
+    private static final String CORE_CONF_DIR = "conf";
+
+    // Service dependencies, injected by the framework
+    private volatile BundleContext m_bundleContext;
+    private volatile ConfigTemplateManager m_configTemplateManager;
+    private volatile LogService m_logService;
+
+    private File m_workDir;
+    private File m_defaultConfigDir;
+
+    public void init() {
+        // Be sure the default configuration directory exists
+        m_defaultConfigDir = new File(m_workDir, "/" + DEFAULT_CONFIG_DIR);
+        m_defaultConfigDir.mkdirs();
+    }
+
+    @SuppressWarnings("unchecked")
+    public void updated(Dictionary dictionary) throws ConfigurationException {
+        if (dictionary != null) {
+            if (dictionary.get(SolrService.CONFIG_WORKDIR) == null) {
+                throw new ConfigurationException("Missing configuration key", 
SolrService.CONFIG_WORKDIR);
+            }
+            File workBaseDir = new File(System.getProperty("user.dir"), 
"work");
+            m_workDir = new File(workBaseDir, (String) 
dictionary.get(SolrService.CONFIG_WORKDIR));
+        }
+    }
+
+    /**
+     * Initialize Solr configuration.
+     */
+    public void initSolr() throws IOException {
+        // Check if the solr.xml file exists. If not, we create the necessary 
configuration files
+        File solrFile = new File(m_workDir, SOLR);
+        if (!solrFile.exists()) {
+            m_workDir.mkdirs();
+            try {
+                // Write the solr.xml file to the solr root directory
+                extractFile(CONF_RESDIR + SOLR, solrFile);
+
+                // Solr uses this system property to find its storage 
location, so set it.
+                System.setProperty("solr.solr.home", 
solrFile.getParentFile().getAbsolutePath());
+
+                // Now copy all default configuration files from the bundle 
JAR to the default config directory
+                extractDefaultConfigurationFiles();
+            } catch (IOException e) {
+                m_logService.log(LogService.LOG_ERROR, "Could not initialize 
Solr configuration", e);
+            }
+        } else {
+            // Solr uses this system property to find its storage location, so 
set it.
+            System.setProperty("solr.solr.home", 
solrFile.getParentFile().getAbsolutePath());
+        }
+    }
+
+
+    /**
+     * Prepare a new core. Copies configuration files from the default 
configuration directory
+     * to the directory created for the new core.
+     * @param coreName
+     * @throws IOException
+     */
+    public void prepareCore(String tenantId, String indexName, InputStream 
schema) throws IOException {
+        // Prepare /conf directory for this core
+        File coreConfDir = getCoreConfDirectory(tenantId, indexName);
+        coreConfDir.mkdirs();
+
+        // Copy default configuration files to this directory
+        copyConfigFile(coreConfDir, SOLR_CONFIG);
+        copyConfigFile(coreConfDir, SYNONYMS);
+        copyConfigFile(coreConfDir, STOPWORDS);
+        copyConfigFile(coreConfDir, PROTWORDS);
+
+        if (schema == null || schema.available() == 0) {
+            // If no schema provided, use default schema
+            copyConfigFile(coreConfDir, SCHEMA);
+        } else {
+            // Custom schema provided, write it to disk
+            File schemaFile = new File(coreConfDir, SCHEMA);
+            SolrUtil.writeToFile(schemaFile, schema);
+        }
+    }
+
+    public void deleteCore(String tenantId, String indexName) {
+        SolrUtil.deleteDirectory(getCoreConfDirectory(tenantId, indexName));
+    }
+
+    public File getWorkDirectory() {
+        return m_workDir;
+    }
+    public File getSolr() {
+        return new File(m_workDir, SOLR);
+    }
+
+    public File getCoreDirectory(String tenantId, String indexName) {
+        String coreDirName = tenantId + "/" + indexName;
+        File coreDir = new File(m_workDir, coreDirName);
+        return coreDir;
+    }
+
+    private File getCoreConfDirectory(String tenantId, String indexName) {
+        return new File(getCoreDirectory(tenantId, indexName), CORE_CONF_DIR);
+    }
+
+    public File getCoreSolrConfig(String tenantId, String indexName) {
+        File coreDir = getCoreConfDirectory(tenantId, indexName);
+        return new File(coreDir, SOLR_CONFIG);
+    }
+
+    public File getCoreSchema(String tenantId, String indexName) {
+        File coreDir = getCoreConfDirectory(tenantId, indexName);
+        return new File(coreDir, SCHEMA);
+    }
+
+    private void copyConfigFile(File coreConfDir, String file) throws 
IOException {
+        File solrConfig = new File(m_defaultConfigDir, file);
+        copyFile(solrConfig, new File(coreConfDir, file));
+    }
+
+    /**
+     * Copied all default configuration files contained by the bundle JAR file 
to the default config
+     * directory.
+     * @throws IOException
+     */
+    public void extractDefaultConfigurationFiles() throws IOException {
+        extractDefaultConfig(SOLR_CONFIG);
+        extractDefaultConfig(SCHEMA);
+        extractDefaultConfig(SYNONYMS);
+        extractDefaultConfig(STOPWORDS);
+        extractDefaultConfig(PROTWORDS);
+    }
+
+    private void extractDefaultConfig(String source) throws IOException {
+        File targetFile = new File(m_defaultConfigDir, source);
+        extractFile(CONF_RESDIR + source, targetFile);
+    }
+
+    private void extractFile(String resource, File target) throws IOException {
+        URL resUrl = m_bundleContext.getBundle().getResource(resource);
+        m_configTemplateManager.writeConfiguration(resUrl, target);
+    }
+
+    private void copyFile(File in, File out) throws IOException {
+        FileChannel inChannel = null;
+        FileChannel outChannel = null;
+        try {
+            inChannel = new FileInputStream(in).getChannel();
+            outChannel = new FileOutputStream(out).getChannel();
+            inChannel.transferTo(0, inChannel.size(), outChannel);
+        }
+        finally {
+            if (inChannel != null) {
+                try {
+                    inChannel.close();
+                } finally {
+                    if (outChannel != null) {
+                        outChannel.close();
+                    }
+                }
+            }
+
+        }
+    }
+}

Modified: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrDaemonServiceImpl.java
==============================================================================
--- 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrDaemonServiceImpl.java
        (original)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrDaemonServiceImpl.java
        Fri Jan 28 17:24:50 2011
@@ -16,10 +16,7 @@
  */
 package org.amdatu.searchandindex.solr.impl;
 
-import java.io.File;
 import java.io.IOException;
-import java.net.URL;
-import java.util.Dictionary;
 
 import org.amdatu.core.config.templates.ConfigTemplateManager;
 import org.amdatu.core.tenant.TenantManagementService;
@@ -33,92 +30,33 @@
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
 import org.osgi.service.log.LogService;
 
 /**
  * Implementation of the {@link SolrService} interface.
  */
-public class SolrDaemonServiceImpl implements SolrService, ManagedService {
-    // Statics
-    private static final String DEFAULT_SOLAR_CONFIG = 
"default_solrconfig.xml";
-    private static final String DEFAULT_SCHEMA = "default_schema.xml";
-    static final String SOLR = "solr.xml";
-    private static final String CONFIG_DIR = "conf";
-
+public class SolrDaemonServiceImpl implements SolrService {
     // Services injected by the Felix dependency manager
     private volatile LogService m_logService;
-    private volatile BundleContext m_bundleContext;
     private volatile DependencyManager m_dependencyManager;
-    private volatile ConfigTemplateManager m_configTemplateManager;
+    private volatile SolrConfiguration m_solrConfig;
 
     // Private members
     private CoreContainer m_coreContainer;
-    private File m_workDir;
-
-    public void init() {
-        try {
-            m_logService.log(LogService.LOG_INFO, "Initializing Solr 
configuration");
 
-            // Initialize storage configuration
-            // Load the URL of the solr.xml and write it file using the config 
template
-            // manager, which automatically replaces configuration entries in 
that file
-            File solrFile = new File(m_workDir, SOLR);
-            if (!solrFile.exists()) {
-                m_workDir.mkdirs();
-                try {
-                    // Write the solr.xml file to the solr root directory
-                    copyConfig(SOLR, solrFile);
-
-                    // Solr uses this system property to find its storage 
location.
-                    System.setProperty("solr.solr.home", 
solrFile.getParentFile().getAbsolutePath());
-
-                    // Update the main config
-                    File mainConfigDir = new File(m_workDir, "/" + CONFIG_DIR);
-                    mainConfigDir.mkdirs();
-
-                    // Write default schema and solr config to /conf
-                    copyConfig(DEFAULT_SOLAR_CONFIG, new File(mainConfigDir, 
"solrconfig.xml"));
-                    copyConfig(DEFAULT_SCHEMA, new File(mainConfigDir, 
"schema.xml"));
-                } catch (IOException e) {
-                    m_logService.log(LogService.LOG_ERROR, "Could not replace 
configuration entries in storage-conf.xml", e);
-                }
-            } else {
-                // Solr uses this system property to find its storage location.
-                System.setProperty("solr.solr.home", 
solrFile.getParentFile().getAbsolutePath());
-            }
-        } catch (Exception e) {
-            m_logService.log(LogService.LOG_ERROR, "Could not create context 
component", e);
-        }
+    public void init() throws IOException {
+        m_solrConfig.initSolr();
     }
 
-    public void start() {
-        try {
-            // Start the Solr daemon
-            startSolrDaemon();
-
-            // Register the Solr API service
-            SolrApiImpl solrApi = registerSolrApi();
+    public void start() throws Exception {
+        // Start the Solr daemon
+        startSolrDaemon();
 
-            // Register the Solr dispatch filter
-            registerRestAPI(solrApi);
-        }
-        catch (Exception e) {
-            m_logService.log(LogService.LOG_ERROR, "Failed to start Solr 
Daemon", e);
-        }
-    }
+        // Register the Solr API service
+        SolrApiImpl solrApi = registerSolrApi();
 
-    @SuppressWarnings("unchecked")
-    public void updated(Dictionary dictionary) throws ConfigurationException {
-        if (dictionary != null) {
-            if (dictionary.get(CONFIG_WORKDIR) == null) {
-                throw new ConfigurationException("Missing configuration key", 
CONFIG_WORKDIR);
-            }
-            File workBaseDir = new File(System.getProperty("user.dir"), 
"work");
-            m_workDir = new File(workBaseDir, (String) 
dictionary.get(CONFIG_WORKDIR));
-        }
+        // Register the Solr dispatch filter
+        registerRestAPI(solrApi);
     }
 
     private void startSolrDaemon() throws Exception {
@@ -162,7 +100,7 @@
 
     // Register the Solr API
     private SolrApiImpl registerSolrApi() {
-        SolrApiImpl solrApiService = new SolrApiImpl(m_workDir, 
m_coreContainer);
+        SolrApiImpl solrApiService = new SolrApiImpl(m_coreContainer, 
m_solrConfig);
         m_dependencyManager.add(m_dependencyManager.createComponent()
             .setImplementation(solrApiService)
             .setInterface(SolrApi.class.getName(), null)
@@ -173,7 +111,7 @@
 
     // Register the REST service
     private void registerRestAPI(SolrApiImpl solrApi) {
-        SolrRestServiceImpl restService = new SolrRestServiceImpl(m_workDir, 
solrApi);
+        SolrRestServiceImpl restService = new SolrRestServiceImpl(solrApi);
         m_dependencyManager.add(m_dependencyManager.createComponent()
             .setImplementation(restService)
             .setInterface(new String[]{SolrRestService.class.getName(), 
ResourceProvider.class.getName()}, null)
@@ -185,9 +123,4 @@
     private ServiceDependency createServiceDependency(Class<?> clazz) {
         return 
m_dependencyManager.createServiceDependency().setService(clazz).setRequired(true);
     }
-
-    private void copyConfig(String source, File target) throws IOException {
-        URL solrConfig = m_bundleContext.getBundle().getResource("conf/" + 
source);
-        m_configTemplateManager.writeConfiguration(solrConfig, target);
-    }
 }

Modified: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrRestServiceImpl.java
==============================================================================
--- 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrRestServiceImpl.java
  (original)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrRestServiceImpl.java
  Fri Jan 28 17:24:50 2011
@@ -16,14 +16,12 @@
  */
 package org.amdatu.searchandindex.solr.impl;
 
-import java.io.File;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Dictionary;
-import java.util.Hashtable;
+import java.util.List;
 
-import javax.servlet.Filter;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.GET;
 import javax.ws.rs.PUT;
@@ -31,6 +29,8 @@
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.CacheControl;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -39,15 +39,17 @@
 import org.amdatu.core.tenant.TenantException;
 import org.amdatu.core.tenant.TenantManagementService;
 import org.amdatu.searchandindex.solr.SolrRestService;
+import org.amdatu.searchandindex.solr.bean.SolrErrorBean;
+import org.amdatu.searchandindex.solr.bean.SolrIndexBean;
+import org.amdatu.searchandindex.solr.bean.SolrTenantIndicesBean;
 import org.amdatu.searchandindex.solr.osgi.Activator;
 import org.amdatu.web.httpcontext.HttpContextServiceFactory;
 import org.amdatu.web.httpcontext.ResourceProvider;
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyManager;
+import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.response.QueryResponse;
-import org.apache.solr.common.SolrDocumentList;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
 import org.osgi.service.log.LogService;
 /**
  * This class provides a REST interface on the Solr index service. The REST 
API can be used to create, update
@@ -66,18 +68,21 @@
     private volatile TenantManagementService m_tenantService;
     private volatile SolrApiImpl m_solrApi;
 
-    // Private members
-    private File m_workDir;
+    // Disable HTTP caching in this REST interface
+    private static CacheControl m_cacheControl;
+    static {
+        m_cacheControl = new CacheControl();
+        m_cacheControl.setNoCache(true);
+    }
 
-    public SolrRestServiceImpl(File workDir, SolrApiImpl solrApi) {
-        m_workDir = workDir;
+    public SolrRestServiceImpl(SolrApiImpl solrApi) {
         m_solrApi = solrApi;
     }
 
     public void init() {
         m_logService.log(LogService.LOG_INFO, "Initializing Solr REST 
interface");
         m_contextComponent = 
m_httpContextServiceFactory.create(m_bundleContext, this);
-        registerSolrDispatchFilter();
+        //registerSolrDispatchFilter();
     }
 
     public void destroy() {
@@ -96,7 +101,7 @@
     }
 
     // Registers the Solr dispatch filter
-    private void registerSolrDispatchFilter() {
+/*    private void registerSolrDispatchFilter() {
         // Create and register a http servlet filter. This filter is mapped on 
.*
         Dictionary<String, Object> filterProperties = new Hashtable<String, 
Object>();
         filterProperties.put("pattern", "/" + Activator.RESOURCE_ID + 
"(|\\?.*|/.*)");
@@ -107,7 +112,7 @@
         m_dependencyManager.add(m_dependencyManager.createComponent()
             .setImplementation(filter)
             .setInterface(Filter.class.getName(), filterProperties));
-    }
+    }*/
 
     /**
      * This method can be used to check the availability of the Index Service.
@@ -115,7 +120,7 @@
      * @return The text "Index service online"
      */
     @GET
-    @Path("{status}")
+    @Path("status")
     @Produces( { MediaType.TEXT_PLAIN })
     public String status() {
         return "Index service online";
@@ -127,61 +132,100 @@
      * @return The text "Index service online"
      */
     @PUT
-    @Path("{index}")
+    @Path("{indexname}")
     @Produces({MediaType.APPLICATION_XML})
-    public Response createIndex(@PathParam("index") final String index, 
@Context final HttpServletRequest request, InputStream is) {
+    public Response createIndex(@PathParam("indexname") final String 
indexname, @Context final HttpServletRequest request, InputStream is) {
+        if (indexname == null || indexname.isEmpty()) {
+            m_logService.log(LogService.LOG_ERROR, "Could not create index '" 
+ indexname + "'");
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        }
         try {
             // Resolve tenant from hostname
             Tenant tenant = resolveTenant(request);
             // This is the tenant for which the index should be created
-            m_solrApi.createIndex(tenant, index);
+            m_solrApi.createIndex(tenant, indexname);
             if (is.available() > 0) {
                 // When more then 0 bytes are available, a document is send 
along with the PUT request
                 // that should be added to this index
-                m_solrApi.updateIndex(tenant, index, is);
+                m_solrApi.updateIndex(tenant, indexname, is);
             }
         } catch (Exception e) {
-            e.printStackTrace();
+            m_logService.log(LogService.LOG_ERROR, "Could not create index '" 
+ indexname + "'", e);
+            throw new WebApplicationException(e);
         }
         return Response.status(Response.Status.OK).build();
     }
 
     /**
      * Perform  Solr query on the specified index.
-     * GET /rest/index/[indexname]/?q=[Solr query]
+     * GET /rest/index/[indexname]?q=[Solr query]
      */
     @GET
-    @Path("{index}")
-    @Produces( { MediaType.TEXT_PLAIN })
-    public String queryIndex(@PathParam("index") final String index, 
@QueryParam("q") final String q,
+    @Path("{indexname}")
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public Response queryIndex(@PathParam("indexname") final String indexname, 
@QueryParam("q") final String q,
         @Context final HttpServletRequest request) {
+        Tenant tenant = null;
+        if (indexname == null || indexname.isEmpty()) {
+            // No indexname passed which is required, return 400 (BAD_REQUEST)
+            m_logService.log(LogService.LOG_ERROR, "Could not query index '" + 
indexname + "'");
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        }
         try {
-            Tenant tenant = resolveTenant(request);
-            QueryResponse response = m_solrApi.queryIndex(tenant, index, q);
-            SolrDocumentList solrDocuments = response.getResults();
-            return "<found>"+solrDocuments.getNumFound()+"</found>";
-        } catch (Exception e) {
-            e.printStackTrace();
+            tenant = resolveTenant(request);
+            if 
(!m_solrApi.getCores(tenant).contains(m_solrApi.getCoreName(tenant, 
indexname))) {
+                // Index does not exist, return a 404 (NOT_FOUND)
+                return 
Response.noContent().cacheControl(m_cacheControl).build();
+            }
+            String query = q;
+            if (query == null || query.isEmpty()) {
+                query = "*:*";
+            }
+            QueryResponse response = m_solrApi.queryIndex(tenant, indexname, 
query);
+            int size = response.getResults().size();
+            SolrIndexBean indexBean = new 
SolrIndexBean(m_solrApi.getCoreName(tenant, indexname), indexname, size);
+            return Response.ok(indexBean).cacheControl(m_cacheControl).build();
+        }
+        catch (TenantException e) {
+            m_logService.log(LogService.LOG_ERROR, "Could not retrieve index 
'" + indexname + "' for tenant '" + tenant + "'", e);
+            throw new WebApplicationException(e);
+        }
+        catch (SolrServerException e) {
+            m_logService.log(LogService.LOG_ERROR, "Could not retrieve index 
'" + indexname + "' for tenant '" + tenant + "'", e);
+            throw new WebApplicationException(e);
         }
-        return "NOPE";
-
     }
 
     /**
-     * Returns a list of all available incdices for this tenant.
+     * Returns a list of all available indices for this tenant.
      * GET /rest/index
      */
     @GET
-    @Produces( { MediaType.TEXT_PLAIN })
-    public String getIndices(@PathParam("index") final String index, @Context 
final HttpServletRequest request) {
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public Response getIndices(@Context final HttpServletRequest request) {
         try {
+            // Resolve tenant and create the tenant indices bean
             Tenant tenant = resolveTenant(request);
-            Collection<String> indices = m_solrApi.getIndices(tenant);
-            return "<found>" + indices + "</found>";
-        } catch (Exception e) {
-            e.printStackTrace();
+            SolrTenantIndicesBean tenantBean = new 
SolrTenantIndicesBean(tenant);
+
+            // Create index beans for each index contained for this tenant
+            List<SolrIndexBean> indexBeans = new ArrayList<SolrIndexBean>();
+            Collection<String> cores = m_solrApi.getCores(tenant);
+            for (String core : cores) {
+                QueryResponse response = m_solrApi.queryCore(core, "*:*");
+                int size = response.getResults().size();
+                indexBeans.add(new SolrIndexBean(core, 
m_solrApi.getIndexName(tenant, core), size));
+            }
+            tenantBean.setIndices(indexBeans);
+            return 
Response.ok(tenantBean).cacheControl(m_cacheControl).build();
+        } catch (TenantException e) {
+            m_logService.log(LogService.LOG_ERROR, "Could not retrieve 
indices", e);
+            throw new WebApplicationException(e);
+        }
+        catch (SolrServerException e) {
+            m_logService.log(LogService.LOG_ERROR, "Could not retrieve 
indices", e);
+            throw new WebApplicationException(e);
         }
-        return "NOPE";
     }
 
     /**
@@ -189,12 +233,16 @@
      * GET /rest/index/[indexname]/schema
      */
     @GET
-    @Path("{index}/schema")
+    @Path("{indexname}/schema")
     @Produces( { MediaType.TEXT_PLAIN })
-    public String getSchema(@PathParam("index") final String index, @Context 
final HttpServletRequest request) {
+    public String getSchema(@PathParam("indexname") final String indexname, 
@Context final HttpServletRequest request) {
+        if (indexname == null || indexname.isEmpty()) {
+            m_logService.log(LogService.LOG_ERROR, "Could not query index '" + 
indexname + "'");
+            return "FAIL";
+        }
         try {
             Tenant tenant = resolveTenant(request);
-            String schema = m_solrApi.getSchema(tenant, index);
+            String schema = m_solrApi.getSchema(tenant, indexname);
             return schema;
         } catch (Exception e) {
             e.printStackTrace();
@@ -202,6 +250,34 @@
         return "NOPE";
     }
 
+    /**
+     * Returns a list of all available incdices for this tenant.
+     * GET /rest/index/[indexname]/schema
+     */
+    @PUT
+    @Path("{indexname}/schema")
+    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public Response putSchema(@PathParam("indexname") final String indexname, 
@Context final HttpServletRequest request, InputStream is) {
+        Tenant tenant = null;
+        try {
+            tenant = resolveTenant(request);
+            if (tenant == null || indexname == null || indexname.isEmpty() || 
is == null || is.available() == 0) {
+                String errorMsg =  "Could not update schema for index '" + 
indexname + "'.";
+                if (is == null || is.available() == 0) {
+                    errorMsg += " No schema provided.";
+                }
+                m_logService.log(LogService.LOG_ERROR, errorMsg);
+                SolrErrorBean errorBean = new SolrErrorBean(errorMsg);
+                return 
Response.status(Response.Status.BAD_REQUEST).entity(errorBean).cacheControl(m_cacheControl).build();
+            }
+            m_solrApi.setSchema(tenant, indexname ,is);
+            return Response.ok().cacheControl(m_cacheControl).build();
+        } catch (Exception e) {
+            m_logService.log(LogService.LOG_ERROR, "Could not update schema 
for index '" + indexname + "' on tenant '" + tenant + "'", e);
+            throw new WebApplicationException(e);
+        }
+    }
+
     private Tenant resolveTenant(HttpServletRequest request) throws 
TenantException {
         // Resolve tenant from hostname
         String serverName = request.getServerName();

Modified: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrTest.java
==============================================================================
--- 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrTest.java
     (original)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrTest.java
     Fri Jan 28 17:24:50 2011
@@ -42,7 +42,7 @@
     private static int ID = 0;
     private static int SIZE = 1;
 
-    public void start() {
+    /*  public void start() {
         try {
             TenantEntity tenant1 = m_tenantService.getTenantById("school_1");
             if (tenant1 == null) {
@@ -68,7 +68,7 @@
         } catch (TenantException e) {
             e.printStackTrace();
         }
-    }
+    }*/
 
     class TestThread extends Thread {
 

Modified: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrUtil.java
==============================================================================
--- 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrUtil.java
     (original)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrUtil.java
     Fri Jan 28 17:24:50 2011
@@ -4,6 +4,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -150,6 +151,42 @@
         return contents;
     }
 
+    public static boolean deleteDirectory(File path) {
+        if( path.exists() ) {
+            File[] files = path.listFiles();
+            for (File file : files) {
+                if(file.isDirectory()) {
+                    deleteDirectory(file);
+                }
+                else {
+                    file.delete();
+                }
+            }
+        }
+        return( path.delete() );
+    }
+
+    public static void writeToFile(File file, InputStream is) throws 
IOException {
+        FileOutputStream fos = null;
+        try {
+            fos = new FileOutputStream(file);
+            byte buf[] = new byte[1024];
+            int len;
+            while((len=is.read(buf))>0) {
+                fos.write(buf,0,len);
+            }
+        } finally {
+            try {
+                if (fos != null) {
+                    fos.close();
+                }
+            } finally {
+                is.close();
+            }
+        }
+    }
+
+
     public static String convertStreamToString(InputStream is) throws 
IOException {
         if (is != null) {
             Writer writer = new StringWriter();

Modified: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/osgi/Activator.java
==============================================================================
--- 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/osgi/Activator.java
    (original)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/osgi/Activator.java
    Fri Jan 28 17:24:50 2011
@@ -18,9 +18,13 @@
 
 import org.amdatu.core.config.templates.ConfigTemplateManager;
 import org.amdatu.core.tenant.TenantManagementService;
+import org.amdatu.searchandindex.solr.RestHttpProxy;
 import org.amdatu.searchandindex.solr.SolrApi;
 import org.amdatu.searchandindex.solr.SolrRestService;
 import org.amdatu.searchandindex.solr.SolrService;
+import org.amdatu.searchandindex.solr.impl.RestHttpProxyImpl;
+import org.amdatu.searchandindex.solr.impl.SolrConfiguration;
+import org.amdatu.searchandindex.solr.impl.SolrConfigurationImpl;
 import org.amdatu.searchandindex.solr.impl.SolrDaemonServiceImpl;
 import org.amdatu.searchandindex.solr.impl.SolrTest;
 import org.apache.felix.dm.DependencyActivatorBase;
@@ -50,12 +54,24 @@
 
         // Create and register the Solr service.
         manager.add(createComponent()
-            .setInterface(SolrService.class.getName(), null)
-            .setImplementation(SolrDaemonServiceImpl.class)
+            .setInterface(RestHttpProxy.class.getName(), null)
+            .setImplementation(RestHttpProxyImpl.class));
+
+        // Create and register the Solr configuration service.
+        manager.add(createComponent()
+            .setInterface(SolrConfiguration.class.getName(), null)
+            .setImplementation(SolrConfigurationImpl.class)
             
.add(createServiceDependency().setService(LogService.class).setRequired(true))
             
.add(createServiceDependency().setService(ConfigTemplateManager.class).setRequired(true))
-            
.add(createServiceDependency().setService(TenantManagementService.class).setRequired(true))
             .add(createConfigurationDependency().setPid(SolrService.PID)));
+
+        // Create and register the Solr service.
+        manager.add(createComponent()
+            .setInterface(SolrService.class.getName(), null)
+            .setImplementation(SolrDaemonServiceImpl.class)
+            
.add(createServiceDependency().setService(SolrConfiguration.class).setRequired(true))
+            
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+            
.add(createServiceDependency().setService(TenantManagementService.class).setRequired(true)));
     }
 
     public void destroy(BundleContext context, DependencyManager manager) 
throws Exception {

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/protwords.txt
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/protwords.txt   
    Fri Jan 28 17:24:50 2011
@@ -0,0 +1,21 @@
+# 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.
+
+#-----------------------------------------------------------------------
+# Use a protected word file to protect against the stemmer reducing two
+# unrelated words to the same base word.
+
+# Some non-words that normally won't be encountered,
+# just to test that they won't be stemmed.
+dontstems
+zwhacky
+

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/schema.xml
==============================================================================
--- (empty file)
+++ sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/schema.xml  
Fri Jan 28 17:24:50 2011
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<!--
+ This is the Solr schema file. This file should be named "schema.xml" and
+ should be in the conf directory under the solr home
+ (i.e. ./solr/conf/schema.xml by default)
+ or located where the classloader for the Solr webapp can find it.
+
+ This example schema is the recommended starting point for users.
+ It should be kept correct and concise, usable out-of-the-box.
+
+ For more information, on how to customize this file, please see
+ http://wiki.apache.org/solr/SchemaXml
+
+ PERFORMANCE NOTE: this schema includes many optional features and should not
+ be used for benchmarking.  To improve performance one could
+  - set stored="false" for all fields possible (esp large fields) when you
+    only need to search on the field but don't need to return the original
+    value.
+  - set indexed="false" if you don't need to search on the field, but only
+    return the field as a result of searching on other indexed fields.
+  - remove all unneeded copyField statements
+  - for best index size and searching performance, set "index" to false
+    for all general text fields, use copyField to copy them to the
+    catchall "text" field, and use that for searching.
+  - For maximum indexing performance, use the StreamingUpdateSolrServer
+    java client.
+  - Remember to run the JVM in server mode, and use a higher logging level
+    that avoids logging every request
+-->
+
+<schema name="amdatu" version="1.2">
+  <!-- attribute "name" is the name of this schema and is only used for 
display purposes.
+       Applications should change this to reflect the nature of the search 
collection.
+       version="1.2" is Solr's version number for the schema syntax and 
semantics.  It should
+       not normally be changed by applications.
+       1.0: multiValued attribute did not exist, all fields are multiValued by 
nature
+       1.1: multiValued attribute introduced, false by default
+       1.2: omitTermFreqAndPositions attribute introduced, true by default 
except for text fields.
+     -->
+
+  <types>
+    <!-- field type definitions. The "name" attribute is
+       just a label to be used by field definitions.  The "class"
+       attribute and any other attributes determine the real
+       behavior of the fieldType.
+         Class names starting with "solr" refer to java classes in the
+       org.apache.solr.analysis package.
+    -->
+
+    <!-- The StrField type is not analyzed, but indexed/stored verbatim.
+       - StrField and TextField support an optional compressThreshold which
+       limits compression (if enabled in the derived fields) to values which
+       exceed a certain size (in characters).
+    -->
+    <fieldType name="string" class="solr.StrField" sortMissingLast="true" 
omitNorms="true"/>
+
+    <!-- boolean type: "true" or "false" -->
+    <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true" 
omitNorms="true"/>
+    <!--Binary data type. The data should be sent/retrieved in as Base64 
encoded Strings -->
+    <fieldtype name="binary" class="solr.BinaryField"/>
+
+    <!-- The optional sortMissingLast and sortMissingFirst attributes are
+         currently supported on types that are sorted internally as strings.
+         This includes 
"string","boolean","sint","slong","sfloat","sdouble","pdate"
+       - If sortMissingLast="true", then a sort on this field will cause 
documents
+         without the field to come after documents with the field,
+         regardless of the requested sort order (asc or desc).
+       - If sortMissingFirst="true", then a sort on this field will cause 
documents
+         without the field to come before documents with the field,
+         regardless of the requested sort order.
+       - If sortMissingLast="false" and sortMissingFirst="false" (the default),
+         then default lucene sorting will be used which places docs without the
+         field first in an ascending sort and last in a descending sort.
+    -->
+
+    <!--
+      Default numeric field types. For faster range queries, consider the 
tint/tfloat/tlong/tdouble types.
+    -->
+    <fieldType name="int" class="solr.TrieIntField" precisionStep="0" 
omitNorms="true" positionIncrementGap="0"/>
+    <fieldType name="float" class="solr.TrieFloatField" precisionStep="0" 
omitNorms="true" positionIncrementGap="0"/>
+    <fieldType name="long" class="solr.TrieLongField" precisionStep="0" 
omitNorms="true" positionIncrementGap="0"/>
+    <fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" 
omitNorms="true" positionIncrementGap="0"/>
+
+    <!--
+     Numeric field types that index each value at various levels of precision
+     to accelerate range queries when the number of values between the range
+     endpoints is large. See the javadoc for NumericRangeQuery for internal
+     implementation details.
+
+     Smaller precisionStep values (specified in bits) will lead to more tokens
+     indexed per value, slightly larger index size, and faster range queries.
+     A precisionStep of 0 disables indexing at different precision levels.
+    -->
+    <fieldType name="tint" class="solr.TrieIntField" precisionStep="8" 
omitNorms="true" positionIncrementGap="0"/>
+    <fieldType name="tfloat" class="solr.TrieFloatField" precisionStep="8" 
omitNorms="true" positionIncrementGap="0"/>
+    <fieldType name="tlong" class="solr.TrieLongField" precisionStep="8" 
omitNorms="true" positionIncrementGap="0"/>
+    <fieldType name="tdouble" class="solr.TrieDoubleField" precisionStep="8" 
omitNorms="true" positionIncrementGap="0"/>
+
+    <!-- The format for this date field is of the form 1995-12-31T23:59:59Z, 
and
+         is a more restricted form of the canonical representation of dateTime
+         http://www.w3.org/TR/xmlschema-2/#dateTime
+         The trailing "Z" designates UTC time and is mandatory.
+         Optional fractional seconds are allowed: 1995-12-31T23:59:59.999Z
+         All other components are mandatory.
+
+         Expressions can also be used to denote calculations that should be
+         performed relative to "NOW" to determine the value, ie...
+
+               NOW/HOUR
+                  ... Round to the start of the current hour
+               NOW-1DAY
+                  ... Exactly 1 day prior to now
+               NOW/DAY+6MONTHS+3DAYS
+                  ... 6 months and 3 days in the future from the start of
+                      the current day
+
+         Consult the DateField javadocs for more information.
+
+         Note: For faster range queries, consider the tdate type
+      -->
+    <fieldType name="date" class="solr.TrieDateField" omitNorms="true" 
precisionStep="0" positionIncrementGap="0"/>
+
+    <!-- A Trie based date field for faster date range queries and date 
faceting. -->
+    <fieldType name="tdate" class="solr.TrieDateField" omitNorms="true" 
precisionStep="6" positionIncrementGap="0"/>
+
+
+    <!--
+      Note:
+      These should only be used for compatibility with existing indexes 
(created with older Solr versions)
+      or if "sortMissingFirst" or "sortMissingLast" functionality is needed. 
Use Trie based fields instead.
+
+      Plain numeric field types that store and index the text
+      value verbatim (and hence don't support range queries, since the
+      lexicographic ordering isn't equal to the numeric ordering)
+    -->
+    <fieldType name="pint" class="solr.IntField" omitNorms="true"/>
+    <fieldType name="plong" class="solr.LongField" omitNorms="true"/>
+    <fieldType name="pfloat" class="solr.FloatField" omitNorms="true"/>
+    <fieldType name="pdouble" class="solr.DoubleField" omitNorms="true"/>
+    <fieldType name="pdate" class="solr.DateField" sortMissingLast="true" 
omitNorms="true"/>
+
+
+    <!--
+      Note:
+      These should only be used for compatibility with existing indexes 
(created with older Solr versions)
+      or if "sortMissingFirst" or "sortMissingLast" functionality is needed. 
Use Trie based fields instead.
+
+      Numeric field types that manipulate the value into
+      a string value that isn't human-readable in its internal form,
+      but with a lexicographic ordering the same as the numeric ordering,
+      so that range queries work correctly.
+    -->
+    <fieldType name="sint" class="solr.SortableIntField" 
sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="slong" class="solr.SortableLongField" 
sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="sfloat" class="solr.SortableFloatField" 
sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="sdouble" class="solr.SortableDoubleField" 
sortMissingLast="true" omitNorms="true"/>
+
+
+    <!-- The "RandomSortField" is not used to store or search any
+         data.  You can declare fields of this type it in your schema
+         to generate pseudo-random orderings of your docs for sorting
+         purposes.  The ordering is generated based on the field name
+         and the version of the index, As long as the index version
+         remains unchanged, and the same field name is reused,
+         the ordering of the docs will be consistent.
+         If you want different psuedo-random orderings of documents,
+         for the same version of the index, use a dynamicField and
+         change the name
+     -->
+    <fieldType name="random" class="solr.RandomSortField" indexed="true" />
+
+    <!-- solr.TextField allows the specification of custom text analyzers
+         specified as a tokenizer and a list of token filters. Different
+         analyzers may be specified for indexing and querying.
+
+         The optional positionIncrementGap puts space between multiple fields 
of
+         this type on the same document, with the purpose of preventing false 
phrase
+         matching across fields.
+
+         For more info on customizing your analyzer chain, please see
+         http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters
+     -->
+
+    <!-- One can also specify an existing Analyzer class that has a
+         default constructor via the class attribute on the analyzer element
+    <fieldType name="text_greek" class="solr.TextField">
+      <analyzer class="org.apache.lucene.analysis.el.GreekAnalyzer"/>
+    </fieldType>
+    -->
+
+    <!-- A text field that only splits on whitespace for exact matching of 
words -->
+    <fieldType name="text_ws" class="solr.TextField" 
positionIncrementGap="100">
+    </fieldType>
+
+    <!-- A text field that uses WordDelimiterFilter to enable splitting and 
matching of
+        words on case-change, alpha numeric boundaries, and non-alphanumeric 
chars,
+        so that a query of "wifi" or "wi fi" could match a document containing 
"Wi-Fi".
+        Synonyms and stopwords are customized by external files, and stemming 
is enabled.
+        -->
+    <fieldType name="text" class="solr.TextField" positionIncrementGap="100">
+    </fieldType>
+
+    <!-- A general unstemmed text field - good if one does not know the 
language of the field -->
+    <fieldType name="textgen" class="solr.TextField" 
positionIncrementGap="100">
+    </fieldType>
+
+    <!-- A general unstemmed text field that indexes tokens normally and also
+         reversed (via ReversedWildcardFilterFactory), to enable more efficient
+   leading wildcard queries. -->
+    <fieldType name="text_rev" class="solr.TextField" 
positionIncrementGap="100">
+    </fieldType>
+
+    <!-- since fields of this type are by default not stored or indexed,
+         any data added to them will be ignored outright.  -->
+    <fieldtype name="ignored" stored="false" indexed="false" 
multiValued="true" class="solr.StrField" />
+ </types>
+
+
+ <fields>
+   <!-- Valid attributes for fields:
+     name: mandatory - the name for the field
+     type: mandatory - the name of a previously defined type from the
+       <types> section
+     indexed: true if this field should be indexed (searchable or sortable)
+     stored: true if this field should be retrievable
+     compressed: [false] if this field should be stored using gzip compression
+       (this will only apply if the field type is compressable; among
+       the standard field types, only TextField and StrField are)
+     multiValued: true if this field may contain multiple values per document
+     omitNorms: (expert) set to true to omit the norms associated with
+       this field (this disables length normalization and index-time
+       boosting for the field, and saves some memory).  Only full-text
+       fields or fields that need an index-time boost need norms.
+     termVectors: [false] set to true to store the term vector for a
+       given field.
+       When using MoreLikeThis, fields used for similarity should be
+       stored for best performance.
+     termPositions: Store position information with the term vector.
+       This will increase storage costs.
+     termOffsets: Store offset information with the term vector. This
+       will increase storage costs.
+     default: a value that should be used if no value is specified
+       when adding a document.
+   -->
+
+   <field name="id" type="string" indexed="true" stored="true" required="true" 
/>
+
+   <!-- catchall field, containing all other searchable text fields 
(implemented
+        via copyField further on in this schema  -->
+   <field name="text" type="text" indexed="true" stored="false" 
multiValued="true"/>
+
+   <field name="timestamp" type="date" indexed="true" stored="false" 
default="NOW" multiValued="false"/>
+
+   <dynamicField name="*_i"  type="sint" indexed="true" stored="false" 
omitNorms="true" multiValued="true"/>
+   <dynamicField name="*_s"  type="string"  indexed="true"  stored="false" 
multiValued="true"/>
+   <dynamicField name="*_l"  type="long"   indexed="true"  stored="false"/>
+   <dynamicField name="*_t"  type="text"    indexed="true"  stored="false"/>
+   <dynamicField name="*_b"  type="boolean" indexed="true"  stored="false"/>
+   <dynamicField name="*_f"  type="float"  indexed="true"  stored="false"/>
+   <dynamicField name="*_d"  type="double" indexed="true"  stored="false"/>
+   <dynamicField name="*_dt" type="date"    indexed="true"  stored="false"/>
+
+   <!-- some trie-coded dynamic fields for faster range queries -->
+   <dynamicField name="*_ti" type="tint"    indexed="true"  stored="false"/>
+   <dynamicField name="*_tl" type="tlong"   indexed="true"  stored="false"/>
+   <dynamicField name="*_tf" type="tfloat"  indexed="true"  stored="false"/>
+   <dynamicField name="*_td" type="tdouble" indexed="true"  stored="false"/>
+   <dynamicField name="*_tdt" type="tdate"  indexed="true"  stored="false"/>
+
+   <dynamicField name="*_pi"  type="pint"    indexed="true"  stored="false"/>
+
+   <dynamicField name="ignored_*" type="ignored" multiValued="true"/>
+   <dynamicField name="attr_*" type="textgen" indexed="true" stored="false" 
multiValued="true"/>
+
+   <dynamicField name="random_*" type="random" />
+
+   <!-- uncomment the following to ignore any fields that don't already match 
an existing
+        field name or dynamic field, rather than reporting them as an error.
+        alternately, change the type="ignored" to some other type e.g. "text" 
if you want
+        unknown fields indexed and/or stored by default -->
+   <!--dynamicField name="*" type="ignored" multiValued="true" /-->
+
+ </fields>
+
+ <!-- Field to use to determine and enforce document uniqueness.
+      Unless this field is marked with required="false", it will be a required 
field
+   -->
+ <uniqueKey>id</uniqueKey>
+
+ <!-- field for the QueryParser to use when an explicit fieldname is absent -->
+ <defaultSearchField>text</defaultSearchField>
+
+ <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
+ <solrQueryParser defaultOperator="OR"/>
+</schema>

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/solrconfig.xml
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/solrconfig.xml  
    Fri Jan 28 17:24:50 2011
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+ 
+ http://wiki.apache.org/solr/SolrConfigXml
+ 
+-->
+
+<config>
+  <indexDefaults>
+    <!-- Sets the amount of RAM that may be used by Lucene indexing
+      for buffering added documents and deletions before they are
+      flushed to the Directory.  -->
+    <ramBufferSizeMB>32</ramBufferSizeMB>
+    <lockType>simple</lockType>
+    <!--
+     Expert:
+    Controls how often Lucene loads terms into memory -->
+    <!--<termIndexInterval>256</termIndexInterval>-->
+  </indexDefaults>
+  
+   <jmx />
+   
+     <query>
+       <maxBooleanClauses>102400</maxBooleanClauses>
+     </query>
+    
+  <updateHandler class="solr.DirectUpdateHandler2" />
+
+  <requestDispatcher handleSelect="true" >
+    <requestParsers enableRemoteStreaming="false" 
multipartUploadLimitInKB="2048" />
+  </requestDispatcher>
+  
+  <requestHandler name="standard" class="solr.StandardRequestHandler" 
default="true">
+    <arr name="last-components">
+    </arr>
+  </requestHandler>
+  
+  <requestHandler name="/update" class="solr.XmlUpdateRequestHandler" />
+  <requestHandler name="/admin/" 
class="org.apache.solr.handler.admin.AdminHandlers" />
+        
+  <!-- config for the admin interface --> 
+  <admin>
+    <defaultQuery>solr</defaultQuery>
+  </admin>
+
+</config>
+

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/stopwords.txt
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/stopwords.txt   
    Fri Jan 28 17:24:50 2011
@@ -0,0 +1,58 @@
+# 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.
+
+#-----------------------------------------------------------------------
+# a couple of test stopwords to test that the words are really being
+# configured from this file:
+stopworda
+stopwordb
+
+#Standard english stop words taken from Lucene's StopAnalyzer
+a
+an
+and
+are
+as
+at
+be
+but
+by
+for
+if
+in
+into
+is
+it
+no
+not
+of
+on
+or
+s
+such
+t
+that
+the
+their
+then
+there
+these
+they
+this
+to
+was
+will
+with
+

Added: 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/synonyms.txt
==============================================================================
--- (empty file)
+++ 
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf/synonyms.txt    
    Fri Jan 28 17:24:50 2011
@@ -0,0 +1,31 @@
+# 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.
+
+#-----------------------------------------------------------------------
+#some test synonym mappings unlikely to appear in real input text
+aaa => aaaa
+bbb => bbbb1 bbbb2
+ccc => cccc1,cccc2
+a\=>a => b\=>b
+a\,a => b\,b
+fooaaa,baraaa,bazaaa
+
+# Some synonym groups specific to this example
+GB,gib,gigabyte,gigabytes
+MB,mib,megabyte,megabytes
+Television, Televisions, TV, TVs
+#notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming
+#after us won't split it into two words.
+
+# Synonym mappings can be used for spelling correction too
+pixima => pixma
+

Reply via email to