diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml
index de3cf06e96..732f4952ad 100644
--- a/config/alfresco/core-services-context.xml
+++ b/config/alfresco/core-services-context.xml
@@ -1035,7 +1035,7 @@
-
+
false
diff --git a/config/alfresco/subsystems/Search/solr/solr-search-context.xml b/config/alfresco/subsystems/Search/solr/solr-search-context.xml
index 258b83f4d3..d0f794b459 100644
--- a/config/alfresco/subsystems/Search/solr/solr-search-context.xml
+++ b/config/alfresco/subsystems/Search/solr/solr-search-context.xml
@@ -56,6 +56,10 @@
+
+
+
+
diff --git a/source/java/org/alfresco/repo/search/impl/solr/SolrAdminHTTPClient.java b/source/java/org/alfresco/repo/search/impl/solr/SolrAdminHTTPClient.java
new file mode 100644
index 0000000000..336507973f
--- /dev/null
+++ b/source/java/org/alfresco/repo/search/impl/solr/SolrAdminHTTPClient.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.search.impl.solr;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.httpclient.HttpClientFactory;
+import org.alfresco.repo.domain.node.NodeDAO;
+import org.alfresco.repo.search.impl.lucene.LuceneQueryParserException;
+import org.alfresco.repo.search.impl.lucene.SolrJSONResultSet;
+import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
+import org.alfresco.service.cmr.search.ResultSet;
+import org.alfresco.service.cmr.search.SearchParameters;
+import org.alfresco.service.cmr.search.SearchParameters.FieldFacet;
+import org.alfresco.service.cmr.search.SearchParameters.FieldFacetMethod;
+import org.alfresco.service.cmr.search.SearchParameters.FieldFacetSort;
+import org.alfresco.service.cmr.search.SearchParameters.SortDefinition;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.apache.commons.codec.net.URLCodec;
+import org.apache.commons.httpclient.Header;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.params.HttpClientParams;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.springframework.extensions.surf.util.I18NUtil;
+
+/**
+ * @author Andy
+ */
+public class SolrAdminHTTPClient
+{
+ static Log s_logger = LogFactory.getLog(SolrAdminHTTPClient.class);
+
+ private String baseUrl;
+
+ private HttpClient httpClient;
+ private HttpClientFactory httpClientFactory;
+
+ public SolrAdminHTTPClient()
+ {
+ }
+
+ public void init()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("/solr/admin/cores");
+ this.baseUrl = sb.toString();
+
+ httpClient = httpClientFactory.getHttpClient();
+ HttpClientParams params = httpClient.getParams();
+ params.setBooleanParameter(HttpClientParams.PREEMPTIVE_AUTHENTICATION, true);
+ httpClient.getState().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), new UsernamePasswordCredentials("admin", "admin"));
+ }
+
+ public void setHttpClientFactory(HttpClientFactory httpClientFactory)
+ {
+ this.httpClientFactory = httpClientFactory;
+ }
+
+ public JSONObject execute(HashMapargs)
+ {
+ try
+ {
+ URLCodec encoder = new URLCodec();
+ StringBuilder url = new StringBuilder();
+
+ for(String key : args.keySet())
+ {
+ String value = args.get(key);
+ if(url.length() == 0)
+ {
+ url.append(baseUrl);
+ url.append("?");
+ url.append(encoder.encode(key, "UTF-8"));
+ url.append("=");
+ url.append(encoder.encode(value, "UTF-8"));
+ }
+ else
+ {
+ url.append("&");
+ url.append(encoder.encode(key, "UTF-8"));
+ url.append("=");
+ url.append(encoder.encode(value, "UTF-8"));
+ }
+
+ }
+
+ PostMethod post = new PostMethod(url.toString());
+
+ try
+ {
+ httpClient.executeMethod(post);
+
+ if(post.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY || post.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)
+ {
+ Header locationHeader = post.getResponseHeader("location");
+ if (locationHeader != null)
+ {
+ String redirectLocation = locationHeader.getValue();
+ post.setURI(new URI(redirectLocation, true));
+ httpClient.executeMethod(post);
+ }
+ }
+
+ if (post.getStatusCode() != HttpServletResponse.SC_OK)
+ {
+ throw new LuceneQueryParserException("Request failed " + post.getStatusCode() + " " + url.toString());
+ }
+
+ Reader reader = new BufferedReader(new InputStreamReader(post.getResponseBodyAsStream()));
+ // TODO - replace with streaming-based solution e.g. SimpleJSON ContentHandler
+ JSONObject json = new JSONObject(new JSONTokener(reader));
+ return json;
+ }
+ finally
+ {
+ post.releaseConnection();
+ }
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new LuceneQueryParserException("", e);
+ }
+ catch (HttpException e)
+ {
+ throw new LuceneQueryParserException("", e);
+ }
+ catch (IOException e)
+ {
+ throw new LuceneQueryParserException("", e);
+ }
+ catch (JSONException e)
+ {
+ throw new LuceneQueryParserException("", e);
+ }
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/search/impl/solr/SolrChildApplicationContextFactory.java b/source/java/org/alfresco/repo/search/impl/solr/SolrChildApplicationContextFactory.java
new file mode 100644
index 0000000000..bc2f395888
--- /dev/null
+++ b/source/java/org/alfresco/repo/search/impl/solr/SolrChildApplicationContextFactory.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2005-2010 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.search.impl.solr;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
+import org.alfresco.repo.search.impl.lucene.LuceneQueryParserException;
+import org.alfresco.service.cmr.repository.datatype.Duration;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * @author Andy
+ */
+public class SolrChildApplicationContextFactory extends ChildApplicationContextFactory
+{
+
+ private static String ALFRESCO_ACTIVE = "tracker.alfresco.active";
+
+ private static String ALFRESCO_LAG = "tracker.alfresco.lag";
+
+ private static String ALFRESCO_LAG_DURATION = "tracker.alfresco.lag.duration";
+
+ private static String ARCHIVE_ACTIVE = "tracker.archive.active";
+
+ private static String ARCHIVE_LAG = "tracker.archive.lag";
+
+ private static String ARCHIVE_LAG_DURATION = "tracker.archive.lag.duration";
+
+ @Override
+ public boolean isUpdateable(String name)
+ {
+ // TODO Auto-generated method stub
+ return super.isUpdateable(name)
+ && !name.equals(SolrChildApplicationContextFactory.ALFRESCO_ACTIVE) && !name.equals(SolrChildApplicationContextFactory.ALFRESCO_LAG)
+ && !name.equals(SolrChildApplicationContextFactory.ALFRESCO_LAG_DURATION) && !name.equals(SolrChildApplicationContextFactory.ARCHIVE_ACTIVE)
+ && !name.equals(SolrChildApplicationContextFactory.ARCHIVE_LAG) && !name.equals(SolrChildApplicationContextFactory.ARCHIVE_LAG_DURATION);
+ }
+
+ @Override
+ public String getProperty(String name)
+ {
+ if (name.equals(SolrChildApplicationContextFactory.ALFRESCO_ACTIVE)
+ || name.equals(SolrChildApplicationContextFactory.ALFRESCO_LAG) || name.equals(SolrChildApplicationContextFactory.ALFRESCO_LAG_DURATION) || name.equals(SolrChildApplicationContextFactory.ARCHIVE_ACTIVE)
+ || name.equals(SolrChildApplicationContextFactory.ARCHIVE_LAG) || name.equals(SolrChildApplicationContextFactory.ARCHIVE_LAG_DURATION))
+ {
+ try
+ {
+ ApplicationContext ctx = getApplicationContext();
+ SolrAdminHTTPClient adminClient = (SolrAdminHTTPClient) ctx.getBean("search.solrAdminHTTPCLient");
+ HashMap args = new HashMap();
+ args.put("action", "SUMMARY");
+ args.put("wt", "json");
+ JSONObject json = adminClient.execute(args);
+ JSONObject summary = json.getJSONObject("Summary");
+
+ Date now = new Date();
+
+ JSONObject alfresco = summary.getJSONObject("alfresco");
+ String alfrescoLag = alfresco.getString("Lag");
+ String alfrescoActive = alfresco.getString("Active");
+ String alfrescoDuration = alfresco.getString("Duration");
+
+
+ JSONObject archive = summary.getJSONObject("archive");
+ String archiveLag = archive.getString("Lag");
+ String archiveActive = archive.getString("Active");
+ String archiveDuration = archive.getString("Duration");
+
+ if (name.equals(SolrChildApplicationContextFactory.ALFRESCO_ACTIVE))
+ {
+ return alfrescoActive;
+ }
+ else if (name.equals(SolrChildApplicationContextFactory.ALFRESCO_LAG))
+ {
+ return alfrescoLag;
+ }
+ else if (name.equals(SolrChildApplicationContextFactory.ALFRESCO_LAG_DURATION))
+ {
+ return alfrescoDuration;
+ }
+ else if (name.equals(SolrChildApplicationContextFactory.ARCHIVE_ACTIVE))
+ {
+ return archiveActive;
+ }
+ else if (name.equals(SolrChildApplicationContextFactory.ARCHIVE_LAG))
+ {
+ return archiveLag;
+ }
+ else if (name.equals(SolrChildApplicationContextFactory.ARCHIVE_LAG_DURATION))
+ {
+ return archiveDuration;
+ }
+ else
+ {
+ return "Unavailable";
+ }
+ }
+ catch (LuceneQueryParserException lqe)
+ {
+ return "Unavailable: " + lqe.getMessage();
+ }
+ catch (JSONException e)
+ {
+ return "Unavailable: " + e.getMessage();
+ }
+ }
+ else
+ {
+ return super.getProperty(name);
+ }
+ }
+
+ @Override
+ public Set getPropertyNames()
+ {
+ Set result = new TreeSet();
+ result.add(SolrChildApplicationContextFactory.ALFRESCO_ACTIVE);
+ result.add(SolrChildApplicationContextFactory.ALFRESCO_LAG);
+ result.add(SolrChildApplicationContextFactory.ALFRESCO_LAG_DURATION);
+ result.add(SolrChildApplicationContextFactory.ARCHIVE_ACTIVE);
+ result.add(SolrChildApplicationContextFactory.ARCHIVE_LAG);
+ result.add(SolrChildApplicationContextFactory.ARCHIVE_LAG_DURATION);
+ result.addAll(super.getPropertyNames());
+ return result;
+ }
+
+ public void setProperty(String name, String value)
+ {
+ if (name.equals(SolrChildApplicationContextFactory.ALFRESCO_ACTIVE)
+ || name.equals(SolrChildApplicationContextFactory.ALFRESCO_LAG) || name.equals(SolrChildApplicationContextFactory.ALFRESCO_LAG_DURATION) || name.equals(SolrChildApplicationContextFactory.ARCHIVE_ACTIVE)
+ || name.equals(SolrChildApplicationContextFactory.ARCHIVE_LAG) || name.equals(SolrChildApplicationContextFactory.ARCHIVE_LAG_DURATION))
+ {
+ throw new IllegalStateException("Illegal write to property \"" + name + "\"");
+ }
+ super.setProperty(name, value);
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/solr/SOLRTrackingComponent.java b/source/java/org/alfresco/repo/solr/SOLRTrackingComponent.java
index d88ac2ef91..cc418f383a 100644
--- a/source/java/org/alfresco/repo/solr/SOLRTrackingComponent.java
+++ b/source/java/org/alfresco/repo/solr/SOLRTrackingComponent.java
@@ -142,4 +142,10 @@ public interface SOLRTrackingComponent
* @param enabled
*/
void setEnabled(boolean enabled);
+
+ /**
+ * Get the last transaction timestamp from the repo
+ * @return
+ */
+ public Long getMaxTxnCommitTime();
}
diff --git a/source/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java b/source/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
index c6070492d2..656f26dd51 100644
--- a/source/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
+++ b/source/java/org/alfresco/repo/solr/SOLRTrackingComponentImpl.java
@@ -796,4 +796,13 @@ public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
more = callback.handleNodeMetaData(row);
}
}
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.solr.SOLRTrackingComponent#getLastTransactionTimestamp()
+ */
+ @Override
+ public Long getMaxTxnCommitTime()
+ {
+ return nodeDAO.getMaxTxnCommitTime();
+ }
}