Merged DEV/SWIFT to HEAD

25629: ALF-7069:
          - changed getNodes to a POST request
          - beefed up unit tests + some performance tests
          ALF-7070:
          - initial checkin, works end-to-end, still work-in-progress
          - unit + performance tests
   25630: ALF-7069: removed files that are no longer needed
   25640: Merged BRANCHES\DEV\SOLR to BRANCHES\DEV\SWIFT
      25079: SOLR check point: ALF-4259: SOLR Integration
      25217: ALF-7068: SOLR 075 Improved cache rebuild performance - delta + query cache warming
      25315: ALF-7068: SOLR 075 Improved cache rebuild performance - delta + query cache warming
      25577: ALF-7068: SOLR 075 Improved cache rebuild performance - delta + query cache warming
      25604: ALF-7068: SOLR 075 Improved cache rebuild performance - delta + query cache warming
      25610: ALF-7068: SOLR 075 Improved cache rebuild performance - delta + query cache warming
   25651: - enabled OpenCMIS server ticket authentication 
          - added OpenCMIS client API (incomplete)
   25667: Merged BRANCHES/DEV/BM to BRANCHES/DEV/SWIFT:
      25030: Repo BM Sprint 1 - example using JMeter (WebDAV & CMIS)
      25054: Repo BM Sprint 1 - milestone 2
      25078: Repo BM sprint 1 - milestone 3 (ALF-6794)
   25675: ALF-7068: SOLR 075 Improved cache rebuild performance - delta + query cache warming
          - fix queries against un-optimized index
   25676: Merged BRANCHES/DEV/BM to BRANCHES/DEV/SWIFT: commit mergeinfo
   25683: RepoBM: OpenCMIS 
          - use shared libs (from 3rd-party project)
          - change default url (from ".../alfresco/opencmis-atom" to ".../alfresco/cmisatom")
   25767: ALF-7339: SOLR 020 Index track and build from SOLR
          - Initial hook up point and proto type for config
   25787: ALF-7070:
          - owner, associations, type conversions
          SOLR Client-side API to call into repository SOLR APIs
   25818: added webscripts root object as an entry point to OpenCMIS client sessions (local and remote)
   25855: Bug fix: keep CMIS connection manager reference

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28089 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2011-05-28 21:31:19 +00:00
parent 4490431ba9
commit 9d194f9363
36 changed files with 3358 additions and 570 deletions

View File

@@ -1,5 +1,6 @@
package org.alfresco.repo.web.scripts.solr;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -14,6 +15,10 @@ import org.alfresco.repo.domain.solr.SOLRDAO.NodeQueryCallback;
import org.alfresco.service.namespace.QName;
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.springframework.extensions.surf.util.Content;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
@@ -49,84 +54,97 @@ public class GetNodes extends DeclarativeWebScript
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
String txnIdsString = req.getParameter("txnIds");
if(txnIdsString == null)
try
{
throw new WebScriptException("txnIds parameter is required for GetNodes");
}
String param = req.getParameter("fromNodeId");
Long fromNodeId = (param == null ? null : Long.valueOf(param));
param = req.getParameter("toNodeId");
Long toNodeId = (param == null ? null : Long.valueOf(param));
param = req.getParameter("excludeAspects");
Set<QName> excludeAspects = null;
if(param != null)
{
String[] excludeAspectsStrings = param.split(",");
excludeAspects = new HashSet<QName>(excludeAspectsStrings.length);
for(String excludeAspect : excludeAspectsStrings)
Content content = req.getContent();
if(content == null)
{
excludeAspects.add(QName.createQName(excludeAspect.trim()));
throw new WebScriptException("Failed to convert request to String");
}
}
param = req.getParameter("includeAspects");
Set<QName> includeAspects = null;
if(param != null)
{
String[] includeAspectsStrings = param.split(",");
includeAspects = new HashSet<QName>(includeAspectsStrings.length);
for(String includeAspect : includeAspectsStrings)
JSONObject o = new JSONObject(content.getContent());
JSONArray aTxnIds = o.has("txnIds") ? o.getJSONArray("txnIds") : null;
Long fromTxnId = o.has("fromTxnId") ? o.getLong("fromTxnId") : null;
Long toTxnId = o.has("toTxnId") ? o.getLong("toTxnId") : null;
Long fromNodeId = o.has("fromNodeId") ? o.getLong("fromNodeId") : null;
Long toNodeId = o.has("toNodeId") ? o.getLong("toNodeId") : null;
Set<QName> excludeAspects = null;
if(o.has("excludeAspects"))
{
includeAspects.add(QName.createQName(includeAspect.trim()));
JSONArray aExcludeAspects = o.getJSONArray("excludeAspects");
excludeAspects = new HashSet<QName>(aExcludeAspects.length());
for(int i = 0; i < aExcludeAspects.length(); i++)
{
excludeAspects.add(QName.createQName(aExcludeAspects.getString(i).trim()));
}
}
Set<QName> includeAspects = null;
if(o.has("includeAspects"))
{
JSONArray aIncludeAspects = o.getJSONArray("includeAspects");
includeAspects = new HashSet<QName>(aIncludeAspects.length());
for(int i = 0; i < aIncludeAspects.length(); i++)
{
includeAspects.add(QName.createQName(aIncludeAspects.getString(i).trim()));
}
}
// 0 or Integer.MAX_VALUE => ignore
int maxResults = o.has("maxResults") ? o.getInt("maxResults") : 0;
String storeProtocol = o.has("storeProtocol") ? o.getString("storeProtocol") : null;
String storeIdentifier = o.has("storeIdentifier") ? o.getString("storeIdentifier") : null;
List<Long> txnIds = null;
if(aTxnIds != null)
{
txnIds = new ArrayList<Long>(aTxnIds.length());
for(int i = 0; i < aTxnIds.length(); i++)
{
txnIds.add(aTxnIds.getLong(i));
}
}
WebNodeQueryCallback nodeQueryCallback = new WebNodeQueryCallback(maxResults);
NodeParameters nodeParameters = new NodeParameters();
nodeParameters.setTransactionIds(txnIds);
nodeParameters.setFromTxnId(fromTxnId);
nodeParameters.setToTxnId(toTxnId);
nodeParameters.setFromNodeId(fromNodeId);
nodeParameters.setToNodeId(toNodeId);
nodeParameters.setExcludeAspects(excludeAspects);
nodeParameters.setIncludeAspects(includeAspects);
nodeParameters.setStoreProtocol(storeProtocol);
nodeParameters.setStoreIdentifier(storeIdentifier);
nodeParameters.setMaxResults(maxResults);
solrDAO.getNodes(nodeParameters, nodeQueryCallback);
Map<String, Object> model = new HashMap<String, Object>(1, 1.0f);
List<Node> nodes = nodeQueryCallback.getNodes();
model.put("nodes", nodes);
if (logger.isDebugEnabled())
{
logger.debug("Result: \n\tRequest: " + req + "\n\tModel: " + model);
}
return model;
}
param = req.getParameter("maxResults");
int maxResults = (param == null ? 0 : Integer.valueOf(param));
param = req.getParameter("storeProtocol");
String storeProtocol = param;
param = req.getParameter("storeIdentifier");
String storeIdentifier = param;
String[] txnIdStrings = txnIdsString.split(",");
List<Long> txnIds = new ArrayList<Long>(txnIdStrings.length);
for(String txnIdString : txnIdStrings)
catch(IOException e)
{
txnIds.add(Long.valueOf(txnIdString.trim()));
throw new WebScriptException("IO exception parsing request", e);
}
WebNodeQueryCallback nodeQueryCallback = new WebNodeQueryCallback(maxResults);
NodeParameters nodeParameters = new NodeParameters();
nodeParameters.setTransactionIds(txnIds);
nodeParameters.setFromNodeId(fromNodeId);
nodeParameters.setToNodeId(toNodeId);
nodeParameters.setExcludeAspects(excludeAspects);
nodeParameters.setIncludeAspects(includeAspects);
nodeParameters.setStoreProtocol(storeProtocol);
nodeParameters.setStoreIdentifier(storeIdentifier);
solrDAO.getNodes(nodeParameters, maxResults, nodeQueryCallback);
Map<String, Object> model = new HashMap<String, Object>(2, 1.0f);
List<Node> nodes = nodeQueryCallback.getNodes();
model.put("nodes", nodes);
model.put("count", nodes.size());
if (logger.isDebugEnabled())
catch(JSONException e)
{
logger.debug("Result: \n\tRequest: " + req + "\n\tModel: " + model);
throw new WebScriptException("Invalid JSON", e);
}
return model;
}
/**
*
* Callback for DAO get nodes query
*
*/
private static class WebNodeQueryCallback implements NodeQueryCallback

View File

@@ -0,0 +1,308 @@
package org.alfresco.repo.web.scripts.solr;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.domain.node.ContentDataWithId;
import org.alfresco.repo.domain.solr.MetaDataResultsFilter;
import org.alfresco.repo.domain.solr.NodeMetaData;
import org.alfresco.repo.domain.solr.NodeMetaDataParameters;
import org.alfresco.repo.domain.solr.SOLRDAO;
import org.alfresco.repo.domain.solr.SOLRDAO.NodeMetaDataQueryCallback;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.SOLRSerializer;
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.springframework.extensions.surf.util.Content;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
// TODO how to hook into bulk loading of nodes + properties + aspects?
// todo url parameter to remove whitespace in results - make it the default?
public class GetNodesMetaData extends DeclarativeWebScript
{
protected static final Log logger = LogFactory.getLog(GetNodesMetaData.class);
private static final int INITIAL_DEFAULT_SIZE = 100;
private static final int BATCH_SIZE = 50;
private SOLRDAO solrDAO;
private SOLRSerializer solrSerializer;
/**
* @param solrDAO the solrDAO to set
*/
public void setSolrDAO(SOLRDAO solrDAO)
{
this.solrDAO = solrDAO;
}
public void setSolrSerializer(SOLRSerializer solrSerializer)
{
this.solrSerializer = solrSerializer;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.Status)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
{
try
{
Content content = req.getContent();
if(content == null)
{
throw new WebScriptException("Failed to convert request to String");
}
JSONObject o = new JSONObject(content.getContent());
List<Long> nodeIds = null;
if(o.has("nodeIds"))
{
JSONArray jsonNodeIds = o.getJSONArray("nodeIds");
nodeIds = new ArrayList<Long>(jsonNodeIds.length());
for(int i = 0; i < jsonNodeIds.length(); i++)
{
Long nodeId = jsonNodeIds.getLong(i);
nodeIds.add(nodeId);
}
}
Long fromNodeId = o.has("fromNodeId") ? o.getLong("fromNodeId") : null;
Long toNodeId = o.has("toNodeId") ? o.getLong("toNodeId") : null;
// 0 or Integer.MAX_VALUE => ignore
int maxResults = o.has("maxResults") ? o.getInt("maxResults") : 0;
int size = 0;
if(maxResults != 0 && maxResults != Integer.MAX_VALUE)
{
size = maxResults;
}
else if(nodeIds != null)
{
size = nodeIds.size();
}
else if(fromNodeId != null && toNodeId != null)
{
if((toNodeId.longValue() - fromNodeId.longValue()) > Integer.MAX_VALUE)
{
throw new WebScriptException("Too many nodes expected, try changing the criteria");
}
size = (int)(toNodeId - fromNodeId);
}
final boolean noSizeCalculated = (size == 0);
// filters, defaults are 'true'
MetaDataResultsFilter filter = new MetaDataResultsFilter();
if(o.has("includeAclId"))
{
filter.setIncludeAclId(o.getBoolean("includeAclId"));
}
if(o.has("includeAspects"))
{
filter.setIncludeAspects(o.getBoolean("includeAspects"));
}
if(o.has("includeNodeRef"))
{
filter.setIncludeNodeRef(o.getBoolean("includeNodeRef"));
}
if(o.has("includeOwner"))
{
filter.setIncludeOwner(o.getBoolean("includeOwner"));
}
if(o.has("includeProperties"))
{
filter.setIncludeProperties(o.getBoolean("includeProperties"));
}
if(o.has("includePaths"))
{
filter.setIncludePaths(o.getBoolean("includePaths"));
}
if(o.has("includeType"))
{
filter.setIncludeType(o.getBoolean("includeType"));
}
if(o.has("includeAssociations"))
{
filter.setIncludeAssociations(o.getBoolean("includeAssociations"));
}
final ArrayList<FreemarkerNodeMetaData> nodesMetaData =
new ArrayList<FreemarkerNodeMetaData>(size > 0 ? size : INITIAL_DEFAULT_SIZE);
NodeMetaDataParameters params = new NodeMetaDataParameters();
params.setNodeIds(nodeIds);
params.setFromNodeId(fromNodeId);
params.setToNodeId(toNodeId);
params.setMaxResults(maxResults);
solrDAO.getNodesMetadata(params, filter, new NodeMetaDataQueryCallback()
{
private int counter = BATCH_SIZE;
private int numBatches = 0;
public boolean handleNodeMetaData(NodeMetaData nodeMetaData)
{
// need to perform data structure conversions that are compatible with Freemarker
// e.g. Serializable -> String, QName -> String (because map keys must be string, number)
FreemarkerNodeMetaData fNodeMetaData = new FreemarkerNodeMetaData(solrSerializer, nodeMetaData);
nodesMetaData.add(fNodeMetaData);
if(noSizeCalculated && --counter == 0)
{
counter = BATCH_SIZE;
nodesMetaData.ensureCapacity(++numBatches*BATCH_SIZE);
}
return true;
}
});
Map<String, Object> model = new HashMap<String, Object>(1, 1.0f);
model.put("nodes", nodesMetaData);
model.put("filter", filter);
if (logger.isDebugEnabled())
{
logger.debug("Result: \n\tRequest: " + req + "\n\tModel: " + model);
}
return model;
}
catch(IOException e)
{
throw new WebScriptException("IO exception parsing request", e);
}
catch(JSONException e)
{
throw new WebScriptException("Invalid JSON", e);
}
}
public static class FreemarkerNodeMetaData
{
private Long nodeId;
private NodeRef nodeRef;
private QName nodeType;
private Long aclId;
private Map<String, Object> properties;
private Set<QName> aspects;
private List<Path> paths;
private List<ChildAssociationRef> childAssocs;
public FreemarkerNodeMetaData(SOLRSerializer solrSerializer, NodeMetaData nodeMetaData)
{
setNodeId(nodeMetaData.getNodeId());
setAclId(nodeMetaData.getAclId());
setNodeRef(nodeMetaData.getNodeRef());
setNodeType(nodeMetaData.getNodeType());
// TODO need to use SOLRTypeConverter to serialize Path
for(Path path : nodeMetaData.getPaths())
{
}
setPaths(nodeMetaData.getPaths());
setChildAssocs(nodeMetaData.getChildAssocs());
setAspects(nodeMetaData.getAspects());
Map<QName, Serializable> props = nodeMetaData.getProperties();
Map<String, Object> properties = (props != null ? new HashMap<String, Object>(props.size()) : null);
for(QName propName : props.keySet())
{
Serializable value = props.get(propName);
if(value instanceof ContentDataWithId)
{
// special case - ContentDataWithId
properties.put(propName.toString(), ((ContentDataWithId)value).getId());
}
else
{
properties.put(propName.toString(), solrSerializer.serialize(propName, value));
}
}
setProperties(properties);
}
public NodeRef getNodeRef()
{
return nodeRef;
}
public void setNodeRef(NodeRef nodeRef)
{
this.nodeRef = nodeRef;
}
public List<Path> getPaths()
{
return paths;
}
public void setPaths(List<Path> paths)
{
this.paths = paths;
}
public QName getNodeType()
{
return nodeType;
}
public void setNodeType(QName nodeType)
{
this.nodeType = nodeType;
}
public Long getNodeId()
{
return nodeId;
}
public void setNodeId(Long nodeId)
{
this.nodeId = nodeId;
}
public Long getAclId()
{
return aclId;
}
public void setAclId(Long aclId)
{
this.aclId = aclId;
}
public Map<String, Object> getProperties()
{
return properties;
}
public void setProperties(Map<String, Object> properties)
{
this.properties = properties;
}
public Set<QName> getAspects()
{
return aspects;
}
public void setAspects(Set<QName> aspects)
{
this.aspects = aspects;
}
public List<ChildAssociationRef> getChildAssocs()
{
return childAssocs;
}
public void setChildAssocs(List<ChildAssociationRef> childAssocs)
{
this.childAssocs = childAssocs;
}
}
}

View File

@@ -0,0 +1,118 @@
package org.alfresco.repo.web.scripts.solr;
import java.util.List;
import java.util.Set;
import org.alfresco.service.namespace.QName;
public class GetNodesParameters
{
private List<Long> transactionIds;
private Long fromNodeId;
private Long toNodeId;
private String storeProtocol;
private String storeIdentifier;
private Set<QName> includeNodeTypes;
private Set<QName> excludeNodeTypes;
private Set<QName> includeAspects;
private Set<QName> excludeAspects;
public boolean getStoreFilter()
{
return (storeProtocol != null || storeIdentifier != null);
}
public void setStoreProtocol(String storeProtocol)
{
this.storeProtocol = storeProtocol;
}
public String getStoreProtocol()
{
return storeProtocol;
}
public void setStoreIdentifier(String storeIdentifier)
{
this.storeIdentifier = storeIdentifier;
}
public String getStoreIdentifier()
{
return storeIdentifier;
}
public void setTransactionIds(List<Long> txnIds)
{
this.transactionIds = txnIds;
}
public List<Long> getTransactionIds()
{
return transactionIds;
}
public Long getFromNodeId()
{
return fromNodeId;
}
public void setFromNodeId(Long fromNodeId)
{
this.fromNodeId = fromNodeId;
}
public Long getToNodeId()
{
return toNodeId;
}
public void setToNodeId(Long toNodeId)
{
this.toNodeId = toNodeId;
}
public Set<QName> getIncludeNodeTypes()
{
return includeNodeTypes;
}
public Set<QName> getExcludeNodeTypes()
{
return excludeNodeTypes;
}
public Set<QName> getIncludeAspects()
{
return includeAspects;
}
public Set<QName> getExcludeAspects()
{
return excludeAspects;
}
public void setIncludeNodeTypes(Set<QName> includeNodeTypes)
{
this.includeNodeTypes = includeNodeTypes;
}
public void setExcludeNodeTypes(Set<QName> excludeNodeTypes)
{
this.excludeNodeTypes = excludeNodeTypes;
}
public void setIncludeAspects(Set<QName> includeAspects)
{
this.includeAspects = includeAspects;
}
public void setExcludeAspects(Set<QName> excludeAspects)
{
this.excludeAspects = excludeAspects;
}
}

View File

@@ -10,7 +10,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
@@ -18,6 +17,8 @@ import org.springframework.extensions.webscripts.WebScriptRequest;
*
* @since 4.0
*/
// TODO check that this does not return incomplete transactions i.e. commitTimeMs is set - does
// the sql account for this?
public class GetTransactions extends DeclarativeWebScript
{
protected static final Log logger = LogFactory.getLog(GetTransactions.class);

View File

@@ -0,0 +1,399 @@
package org.alfresco.repo.web.scripts.solr;
import java.io.IOException;
import java.io.Writer;
import java.util.Stack;
/**
* Fast and simple JSON stream writer. Wraps a Writer to output a JSON object stream.
* No intermediate objects are created - writes are immediate to the underlying stream.
* Quoted and correct JSON encoding is performed on string values, - encoding is
* not performed on key names - it is assumed they are simple strings. The developer must
* call JSONWriter.encodeJSONString() on the key name if required.
*
* @author Kevin Roast
* @author Steve Glover
*
* Adapted from org.springframework.extensions.webscripts.json.
* - added writeValue methods for class versions of primitives
*/
public final class JSONWriter
{
private Writer out;
private Stack<Boolean> stack = new Stack<Boolean>();
/**
* Constructor
*
* @param out The Writer to immediately append values to (no internal buffering)
*/
public JSONWriter(Writer out)
{
this.out = out;
stack.push(Boolean.FALSE);
}
/**
* Start an array structure, the endArray() method must be called later.
* NOTE: Within the array, either output objects or use the single arg writeValue() method.
*/
public void startArray() throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write("[");
stack.pop();
stack.push(Boolean.TRUE);
stack.push(Boolean.FALSE);
}
/**
* End an array structure.
*/
public void endArray() throws IOException
{
out.write("]");
stack.pop();
}
/**
* Start an object structure, the endObject() method must be called later.
*/
public void startObject() throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write("{");
stack.pop();
stack.push(Boolean.TRUE);
stack.push(Boolean.FALSE);
}
/**
* End an object structure.
*/
public void endObject() throws IOException
{
out.write("}");
stack.pop();
}
/**
* Start a value (outputs just a name key), the endValue() method must be called later.
* NOTE: follow with an array or object only.
*/
public void startValue(String name) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": ");
stack.pop();
stack.push(Boolean.TRUE);
stack.push(Boolean.FALSE);
}
/**
* End a value that was started with startValue()
*/
public void endValue()
{
stack.pop();
}
/**
* Output a JSON string name and value pair.
*/
public void writeValue(String name, String value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": \"");
out.write(encodeJSONString(value));
out.write('"');
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON number name and value pair.
*/
public void writeValue(String name, int value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": ");
out.write(Integer.toString(value));
stack.pop();
stack.push(Boolean.TRUE);
}
public void writeValue(String name, Integer value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": ");
out.write(value.toString());
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON number name and value pair.
*/
public void writeValue(String name, float value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": ");
out.write(Float.toString(value));
stack.pop();
stack.push(Boolean.TRUE);
}
public void writeValue(String name, Float value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": ");
out.write(value.toString());
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON boolean name and value pair.
*/
public void writeValue(String name, boolean value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": ");
out.write(Boolean.toString(value));
stack.pop();
stack.push(Boolean.TRUE);
}
public void writeValue(String name, Boolean value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": ");
out.write(value.toString());
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON string value.
* NOTE: no name is written - call from within an array structure.
*/
public void writeValue(String value) throws IOException
{
if (stack.peek() == true) out.write(",");
out.write('"');
out.write(encodeJSONString(value));
out.write('"');
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON number value.
* NOTE: no name is written - call from within an array structure.
*/
public void writeValue(int value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write(Integer.toString(value));
stack.pop();
stack.push(Boolean.TRUE);
}
public void writeValue(Integer value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write(value.toString());
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON long value.
* NOTE: no name is written - call from within an array structure.
*/
public void writeValue(long value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write(Long.toString(value));
stack.pop();
stack.push(Boolean.TRUE);
}
public void writeValue(Long value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write(value.toString());
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON number value.
* NOTE: no name is written - call from within an array structure.
*/
public void writeValue(float value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write(Float.toString(value));
stack.pop();
stack.push(Boolean.TRUE);
}
public void writeValue(Float value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write(value.toString());
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON boolean value.
* NOTE: no name is written - call from within an array structure.
*/
public void writeValue(boolean value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write(Boolean.toString(value));
stack.pop();
stack.push(Boolean.TRUE);
}
public void writeValue(Boolean value) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write(value.toString());
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON null value.
* NOTE: no name is written - call from within an array structure.
*/
public void writeNullValue() throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write("null");
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Output a JSON null value.
*/
public void writeNullValue(String name) throws IOException
{
if (stack.peek() == true) out.write(", ");
out.write('"');
out.write(name);
out.write("\": null");
stack.pop();
stack.push(Boolean.TRUE);
}
/**
* Safely encode a JSON string value.
* @return encoded string, null is handled and returned as "".
*/
public static String encodeJSONString(final String s)
{
if (s == null || s.length() == 0)
{
return "";
}
StringBuilder sb = null; // create on demand
String enc;
char c;
int len = s.length();
for (int i = 0; i < len; i++)
{
enc = null;
c = s.charAt(i);
switch (c)
{
case '\\':
enc = "\\\\";
break;
case '"':
enc = "\\\"";
break;
case '/':
enc = "\\/";
break;
case '\b':
enc = "\\b";
break;
case '\t':
enc = "\\t";
break;
case '\n':
enc = "\\n";
break;
case '\f':
enc = "\\f";
break;
case '\r':
enc = "\\r";
break;
default:
if (((int)c) >= 0x80)
{
//encode all non basic latin characters
String u = "000" + Integer.toHexString((int)c);
enc = "\\u" + u.substring(u.length() - 4);
}
break;
}
if (enc != null)
{
if (sb == null)
{
String soFar = s.substring(0, i);
sb = new StringBuilder(i + 8);
sb.append(soFar);
}
sb.append(enc);
}
else
{
if (sb != null)
{
sb.append(c);
}
}
}
if (sb == null)
{
return s;
}
else
{
return sb.toString();
}
}
}

View File

@@ -0,0 +1,76 @@
package org.alfresco.repo.web.scripts.solr;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.namespace.QName;
public class NodeMetaData
{
private long id;
private NodeRef nodeRef;
private QName type;
private long aclId;
private Map<QName, Serializable> properties;
private Set<QName> aspects;
private Path paths;
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public NodeRef getNodeRef()
{
return nodeRef;
}
public void setNodeRef(NodeRef nodeRef)
{
this.nodeRef = nodeRef;
}
public QName getType()
{
return type;
}
public void setType(QName type)
{
this.type = type;
}
public long getAclId()
{
return aclId;
}
public void setAclId(long aclId)
{
this.aclId = aclId;
}
public Map<QName, Serializable> getProperties()
{
return properties;
}
public void setProperties(Map<QName, Serializable> properties)
{
this.properties = properties;
}
public Set<QName> getAspects()
{
return aspects;
}
public void setAspects(Set<QName> aspects)
{
this.aspects = aspects;
}
public Path getPaths()
{
return paths;
}
public void setPaths(Path paths)
{
this.paths = paths;
}
}

View File

@@ -0,0 +1,257 @@
package org.alfresco.repo.web.scripts.solr.test;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.node.ContentDataWithId;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.admin.RepoAdminService;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MLText;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.Period;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyMap;
import org.alfresco.util.SOLRDeserializer;
import org.alfresco.util.SOLRSerializer;
public class SOLRSerializerTests extends BaseWebScriptTest
{
static final String SOLR_TEST_MODEL_1_0_URI = "http://www.alfresco.org/model/solrtest/1.0";
static final QName TYPE_TEST_OBJECT = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "testobject");
static final QName PROP_MLTEXT = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "mlTextProp");
static final QName PROP_BOOL = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "boolProp");
static final QName PROP_LONG = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "longProp");
static final QName PROP_FLOAT = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "floatProp");
static final QName PROP_DOUBLE = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "doubleProp");
static final QName PROP_DATE = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "dateProp");
static final QName PROP_DATETIME = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "dateTimeProp");
static final QName PROP_QNAME = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "qnameProp");
static final QName PROP_NODEREF = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "nodeRefProp");
static final QName PROP_CHILDASSOC = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "childAssocProp");
static final QName PROP_ASSOC = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "assocProp");
static final QName PROP_PATH = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "pathProp");
static final QName PROP_CATEGORY = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "categoryProp");
static final QName PROP_LOCALE = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "localeProp");
static final QName PROP_PERIOD = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "periodProp");
static final QName PROP_ANY = QName.createQName(SOLR_TEST_MODEL_1_0_URI, "anyProp");
private AuthenticationComponent authenticationComponent;
private TransactionService transactionService;
private RetryingTransactionHelper txnHelper;
private NodeService nodeService;
private FileFolderService fileFolderService;
private ContentService contentService;
private DictionaryService dictionaryService;
private RepoAdminService repoAdminService;
private SOLRSerializer solrSerializer;
private SOLRDeserializer solrDeserializer;
private StoreRef storeRef;
private NodeRef rootNodeRef;
@Override
public void setUp() throws Exception
{
ServiceRegistry serviceRegistry = (ServiceRegistry) getServer().getApplicationContext().getBean(ServiceRegistry.SERVICE_REGISTRY);
transactionService = serviceRegistry.getTransactionService();
txnHelper = transactionService.getRetryingTransactionHelper();
fileFolderService = serviceRegistry.getFileFolderService();
contentService = serviceRegistry.getContentService();
nodeService = serviceRegistry.getNodeService();
dictionaryService = serviceRegistry.getDictionaryService();
authenticationComponent = (AuthenticationComponent)getServer().getApplicationContext().getBean("authenticationComponent");
repoAdminService = (RepoAdminService)getServer().getApplicationContext().getBean("repoAdminService");
solrSerializer = (SOLRSerializer)getServer().getApplicationContext().getBean("solrSerializer");
solrDeserializer = new SOLRDeserializer(dictionaryService);
authenticationComponent.setSystemUserAsCurrentUser();
InputStream modelStream = getClass().getClassLoader().getResourceAsStream("solr/solr-test-model.xml");
repoAdminService.deployModel(modelStream, "solr-test-model");
storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.currentTimeMillis());
rootNodeRef = nodeService.getRootNode(storeRef);
}
private NodeRef solrNode;
private Date date;
private MLText mlText;
private ChildAssociationRef childAssoc;
private AssociationRef assoc;
private List<NodeRef> multiCategory;
private NodeRef category;
private static String[] mlOrderable_en = new String[] { "AAAA BBBB", "EEEE FFFF", "II", "KK", "MM", "OO", "QQ", "SS", "UU", "AA", "CC" };
private static String[] mlOrderable_fr = new String[] { "CCCC DDDD", "GGGG HHHH", "JJ", "LL", "NN", "PP", "RR", "TT", "VV", "BB", "DD" };
private MLText makeMLText()
{
return makeMLText(0);
}
private MLText makeMLText(int position)
{
MLText ml = new MLText();
ml.addValue(Locale.ENGLISH, mlOrderable_en[position]);
ml.addValue(Locale.FRENCH, mlOrderable_fr[position]);
return ml;
}
private void buildTransaction()
{
PropertyMap props = new PropertyMap();
props.put(ContentModel.PROP_NAME, "Container1");
NodeRef container = nodeService.createNode(
rootNodeRef,
ContentModel.ASSOC_CHILDREN,
ContentModel.ASSOC_CHILDREN,
ContentModel.TYPE_FOLDER,
props).getChildRef();
FileInfo contentInfo = fileFolderService.create(container, "SolrNode", TYPE_TEST_OBJECT);
solrNode = contentInfo.getNodeRef();
ContentWriter writer = contentService.getWriter(solrNode, ContentModel.PROP_CONTENT, true);
writer.putContent("Some Content");
date = new Date();
mlText = makeMLText();
childAssoc = new ChildAssociationRef(ContentModel.ASSOC_CHILDREN,
new NodeRef("testProtocol", "testID", "abcde"),
QName.createQName("testProtocol", "testID"),
new NodeRef("testProtocol", "testID", "xyz"));
assoc = new AssociationRef(
new NodeRef("testProtocol", "testID", "abcde"),
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "parts"),
new NodeRef("testProtocol", "testID", "xyz"));
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
properties.put(PROP_BOOL, Boolean.TRUE);
properties.put(PROP_LONG, Long.valueOf(42));
properties.put(PROP_FLOAT, Float.valueOf(42.0f));
properties.put(PROP_DOUBLE, Double.valueOf(42.0));
properties.put(PROP_DATE, date);
properties.put(PROP_DATETIME, date);
properties.put(PROP_NODEREF, container);
properties.put(PROP_LOCALE, Locale.ITALY);
properties.put(PROP_QNAME, PROP_QNAME);
//properties.put(PROP_VERSION, new VersionNumber("1.0"));
properties.put(PROP_PERIOD, new Period("period|12"));
Path path = new Path();
Path.Element element0 = new Path.ChildAssocElement(new ChildAssociationRef(null, null, null, new NodeRef("testProtocol", "testID", "abcde")));
path.prepend(element0);
properties.put(PROP_PATH, path);
properties.put(PROP_ASSOC, assoc);
category = new NodeRef("testProtocol", "testID", "cat1");
properties.put(PROP_CATEGORY, (Serializable)category);
properties.put(PROP_CHILDASSOC, childAssoc);
properties.put(PROP_MLTEXT, mlText);
nodeService.setProperties(solrNode, properties);
}
public void testAll()
{
txnHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
buildTransaction();
Serializable value = nodeService.getProperty(solrNode, ContentModel.PROP_NAME);
Object serialized = solrSerializer.serialize(ContentModel.PROP_NAME, value);
Serializable deserialized = solrDeserializer.deserialize(ContentModel.PROP_NAME, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_MLTEXT);
serialized = solrSerializer.serialize(PROP_MLTEXT, value);
deserialized = solrDeserializer.deserialize(PROP_MLTEXT, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, ContentModel.PROP_CONTENT);
assertTrue("Expected ContentDataId, got " + value.getClass().getName(), value instanceof ContentDataWithId);
serialized = solrSerializer.serialize(ContentModel.PROP_CONTENT, value);
deserialized = solrDeserializer.deserialize(ContentModel.PROP_CONTENT, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_BOOL);
serialized = solrSerializer.serialize(PROP_BOOL, value);
deserialized = solrDeserializer.deserialize(PROP_BOOL, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_DATE);
assertTrue("Expected Date object, got " + value.getClass().getName(), value instanceof Date);
serialized = solrSerializer.serialize(PROP_DATE, value);
deserialized = solrDeserializer.deserialize(PROP_DATE, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_DATETIME);
assertTrue("Expected Date object, got " + value.getClass().getName(), value instanceof Date);
serialized = solrSerializer.serialize(PROP_DATETIME, value);
deserialized = solrDeserializer.deserialize(PROP_DATETIME, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_DOUBLE);
assertTrue("Expected Double object, got " + value.getClass().getName(), value instanceof Double);
serialized = solrSerializer.serialize(PROP_DATETIME, value);
deserialized = solrDeserializer.deserialize(PROP_DATETIME, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_FLOAT);
assertTrue("Expected Float object, got " + value.getClass().getName(), value instanceof Float);
serialized = solrSerializer.serialize(PROP_FLOAT, value);
deserialized = solrDeserializer.deserialize(PROP_FLOAT, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_LONG);
assertTrue("Expected Long object, got " + value.getClass().getName(), value instanceof Long);
serialized = solrSerializer.serialize(PROP_LONG, value);
deserialized = solrDeserializer.deserialize(PROP_LONG, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_CHILDASSOC);
serialized = solrSerializer.serialize(PROP_CHILDASSOC, value);
deserialized = solrDeserializer.deserialize(PROP_CHILDASSOC, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_ASSOC);
serialized = solrSerializer.serialize(PROP_ASSOC, value);
deserialized = solrDeserializer.deserialize(PROP_ASSOC, serialized);
assertEquals(value, deserialized);
value = nodeService.getProperty(solrNode, PROP_CATEGORY);
serialized = solrSerializer.serialize(PROP_ASSOC, value);
deserialized = solrDeserializer.deserialize(PROP_ASSOC, serialized);
assertEquals(value, deserialized);
return null;
}
});
}
}