Java tutorial
/* * #%L * Alfresco Remote API * %% * Copyright (C) 2005 - 2016 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of * the paid license agreement will prevail. Otherwise, the software is * provided under the following open source license terms: * * 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 <http://www.gnu.org/licenses/>. * #L% */ package org.alfresco.repo.web.scripts.solr; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.domain.node.ContentDataWithId; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.MLText; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.Path; import org.alfresco.service.cmr.repository.Path.AttributeElement; import org.alfresco.service.cmr.repository.Path.ChildAssocElement; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.repository.datatype.TypeConverter; import org.alfresco.service.cmr.repository.datatype.TypeConverter.Converter; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.util.PropertyCheck; 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.webscripts.json.JSONUtils; /** * SOLR conversions of values to JSON-compatible <tt>String</tt>. * * @since 4.0 */ /* package */ class SOLRSerializer { protected static final Log logger = LogFactory.getLog(SOLRSerializer.class); private JSONUtils jsonUtils = new JSONUtils(); private Set<QName> NUMBER_TYPES; private DictionaryService dictionaryService; private NamespaceService namespaceService; private SOLRTypeConverter typeConverter; public void init() { PropertyCheck.mandatory(this, "dictionaryService", dictionaryService); PropertyCheck.mandatory(this, "namespaceService", namespaceService); NUMBER_TYPES = new HashSet<QName>(4); NUMBER_TYPES.add(DataTypeDefinition.DOUBLE); NUMBER_TYPES.add(DataTypeDefinition.FLOAT); NUMBER_TYPES.add(DataTypeDefinition.INT); NUMBER_TYPES.add(DataTypeDefinition.LONG); typeConverter = new SOLRTypeConverter(namespaceService); } public void setDictionaryService(DictionaryService dictionaryService) { this.dictionaryService = dictionaryService; } public void setNamespaceService(NamespaceService namespaceService) { this.namespaceService = namespaceService; } public String serializeToJSONString(Serializable value) { if (value != null && typeConverter.INSTANCE.getConverter(value.getClass(), String.class) == null) { // There is no converter return value.toString(); } else { return typeConverter.INSTANCE.convert(String.class, value); } } public <T> T serializeValue(Class<T> targetClass, Object value) throws JSONException { return typeConverter.INSTANCE.convert(targetClass, value); } @SuppressWarnings("unchecked") public PropertyValue serialize(QName propName, Serializable value) throws IOException, JSONException { if (value == null) { return new PropertyValue(false, "null"); } PropertyDefinition propertyDef = dictionaryService.getProperty(propName); if (propertyDef == null) { // Treat it as text return new PropertyValue(true, serializeToJSONString(value)); } DataTypeDefinition dataType = propertyDef.getDataType(); QName dataTypeName = dataType.getName(); if (propertyDef.isMultiValued()) { if (!(value instanceof Collection)) { throw new IllegalArgumentException( "Multi value: expected a collection, got " + value.getClass().getName()); } Collection<Serializable> c = (Collection<Serializable>) value; JSONArray body = new JSONArray(); for (Serializable o : c) { if (dataTypeName.equals(DataTypeDefinition.MLTEXT)) { MLText source = (MLText) o; JSONArray array = new JSONArray(); for (Locale locale : source.getLocales()) { JSONObject json = new JSONObject(); json.put("locale", DefaultTypeConverter.INSTANCE.convert(String.class, locale)); json.put("value", source.getValue(locale)); array.put(json); } body.put(array); } else if (dataTypeName.equals(DataTypeDefinition.CONTENT)) { throw new RuntimeException("Multi-valued content properties are not supported"); } else { body.put(serializeToJSONString(o)); } } return new PropertyValue(false, body.toString()); } else { boolean encodeString = true; if (dataTypeName.equals(DataTypeDefinition.MLTEXT)) { encodeString = false; } else if (dataTypeName.equals(DataTypeDefinition.CONTENT)) { encodeString = false; } else { encodeString = true; } String sValue = null; if (value instanceof String && encodeString) { sValue = (String) jsonUtils.encodeJSONString(value); } else { sValue = serializeToJSONString(value); } return new PropertyValue(encodeString, sValue); } } @SuppressWarnings("rawtypes") private class SOLRTypeConverter { private NamespaceService namespaceService; TypeConverter INSTANCE = new TypeConverter(); @SuppressWarnings("unchecked") SOLRTypeConverter(NamespaceService namespaceService) { this.namespaceService = namespaceService; // add all default converters to this converter // TODO find a better way of doing this Map<Class<?>, Map<Class<?>, Converter<?, ?>>> converters = DefaultTypeConverter.INSTANCE .getConverters(); for (Class<?> source : converters.keySet()) { Map<Class<?>, Converter<?, ?>> converters1 = converters.get(source); for (Class dest : converters1.keySet()) { Converter converter = converters1.get(dest); INSTANCE.addConverter(source, dest, converter); } } // MLText INSTANCE.addConverter(MLText.class, String.class, new TypeConverter.Converter<MLText, String>() { public String convert(MLText source) { try { JSONArray array = new JSONArray(); for (Locale locale : source.getLocales()) { JSONObject json = new JSONObject(); json.put("locale", DefaultTypeConverter.INSTANCE.convert(String.class, locale)); json.put("value", source.getValue(locale)); array.put(json); } return array.toString(3); } catch (JSONException e) { throw new AlfrescoRuntimeException("Unable to serialize content data to JSON", e); } } }); // QName INSTANCE.addConverter(QName.class, String.class, new TypeConverter.Converter<QName, String>() { public String convert(QName source) { return source.toString(); } }); // content INSTANCE.addConverter(ContentDataWithId.class, String.class, new TypeConverter.Converter<ContentDataWithId, String>() { public String convert(ContentDataWithId source) { JSONObject json = new JSONObject(); try { json.put("contentId", String.valueOf(source.getId())); String locale = INSTANCE.convert(String.class, source.getLocale()); json.put("locale", locale == null ? JSONObject.NULL : locale); String encoding = source.getEncoding(); json.put("encoding", encoding == null ? JSONObject.NULL : encoding); String mimetype = source.getMimetype(); json.put("mimetype", mimetype == null ? JSONObject.NULL : mimetype); json.put("size", String.valueOf(source.getSize())); return json.toString(3); } catch (JSONException e) { throw new AlfrescoRuntimeException("Unable to serialize content data to JSON", e); } } }); INSTANCE.addConverter(ContentData.class, String.class, new TypeConverter.Converter<ContentData, String>() { public String convert(ContentData source) { JSONObject json = new JSONObject(); try { String locale = INSTANCE.convert(String.class, source.getLocale()); json.put("locale", locale == null ? JSONObject.NULL : locale); String encoding = source.getEncoding(); json.put("encoding", encoding == null ? JSONObject.NULL : encoding); String mimetype = source.getMimetype(); json.put("mimetype", mimetype == null ? JSONObject.NULL : mimetype); json.put("size", String.valueOf(source.getSize())); return json.toString(3); } catch (JSONException e) { throw new AlfrescoRuntimeException("Unable to serialize content data to JSON", e); } } }); // node refs INSTANCE.addConverter(NodeRef.class, String.class, new TypeConverter.Converter<NodeRef, String>() { public String convert(NodeRef source) { return source.toString(); } }); INSTANCE.addConverter(String.class, NodeRef.class, new TypeConverter.Converter<String, NodeRef>() { public NodeRef convert(String source) { return new NodeRef(source); } }); // paths INSTANCE.addConverter(AttributeElement.class, String.class, new TypeConverter.Converter<AttributeElement, String>() { public String convert(AttributeElement source) { return source.toString(); } }); INSTANCE.addConverter(ChildAssocElement.class, String.class, new TypeConverter.Converter<ChildAssocElement, String>() { public String convert(ChildAssocElement source) { return source.getRef().toString(); } }); INSTANCE.addConverter(Path.DescendentOrSelfElement.class, String.class, new TypeConverter.Converter<Path.DescendentOrSelfElement, String>() { public String convert(Path.DescendentOrSelfElement source) { return source.toString(); } }); INSTANCE.addConverter(Path.ParentElement.class, String.class, new TypeConverter.Converter<Path.ParentElement, String>() { public String convert(Path.ParentElement source) { return source.toString(); } }); INSTANCE.addConverter(Path.SelfElement.class, String.class, new TypeConverter.Converter<Path.SelfElement, String>() { public String convert(Path.SelfElement source) { return source.toString(); } }); INSTANCE.addConverter(String.class, AttributeElement.class, new TypeConverter.Converter<String, AttributeElement>() { public AttributeElement convert(String source) { return new Path.AttributeElement(source); } }); INSTANCE.addConverter(String.class, ChildAssocElement.class, new TypeConverter.Converter<String, ChildAssocElement>() { public ChildAssocElement convert(String source) { return new Path.ChildAssocElement(INSTANCE.convert(ChildAssociationRef.class, source)); } }); INSTANCE.addConverter(String.class, Path.DescendentOrSelfElement.class, new TypeConverter.Converter<String, Path.DescendentOrSelfElement>() { public Path.DescendentOrSelfElement convert(String source) { return new Path.DescendentOrSelfElement(); } }); INSTANCE.addConverter(String.class, Path.ParentElement.class, new TypeConverter.Converter<String, Path.ParentElement>() { public Path.ParentElement convert(String source) { return new Path.ParentElement(); } }); INSTANCE.addConverter(String.class, Path.SelfElement.class, new TypeConverter.Converter<String, Path.SelfElement>() { public Path.SelfElement convert(String source) { return new Path.SelfElement(); } }); INSTANCE.addConverter(Path.class, List.class, new TypeConverter.Converter<Path, List>() { public List convert(Path source) { List<String> pathArray = new ArrayList<String>(source.size()); for (Path.Element element : source) { pathArray.add(INSTANCE.convert(String.class, element)); } return pathArray; } }); INSTANCE.addConverter(Path.class, String.class, new TypeConverter.Converter<Path, String>() { public String convert(Path source) { return source.toString(); } }); // associations INSTANCE.addConverter(ChildAssociationRef.class, String.class, new TypeConverter.Converter<ChildAssociationRef, String>() { public String convert(ChildAssociationRef source) { return source.toString(); } }); INSTANCE.addConverter(String.class, ChildAssociationRef.class, new TypeConverter.Converter<String, ChildAssociationRef>() { public ChildAssociationRef convert(String source) { return new ChildAssociationRef(source); } }); INSTANCE.addConverter(AssociationRef.class, String.class, new TypeConverter.Converter<AssociationRef, String>() { public String convert(AssociationRef source) { return source.toString(); } }); INSTANCE.addConverter(String.class, AssociationRef.class, new TypeConverter.Converter<String, AssociationRef>() { public AssociationRef convert(String source) { return new AssociationRef(source); } }); INSTANCE.addConverter(Number.class, String.class, new TypeConverter.Converter<Number, String>() { public String convert(Number source) { return source.toString(); } }); INSTANCE.addConverter(Boolean.class, String.class, new TypeConverter.Converter<Boolean, String>() { public String convert(Boolean source) { return source.toString(); } }); } } }