diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index e379a0afb4..777d40903c 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -278,3 +278,6 @@ patch.authorityMigration.result=Migrated {0} authorities to the spaces store. patch.authorityDefaultZonesPatch.description=Adds groups and people to the appropriate zones for wcm, share and everything else. patch.authorityDefaultZonesPatch.result=Unzoned groups and people added to the default zones. +patch.fixNameCrcValues.description=Fixes name CRC32 values to match UTF-8 encoding. +patch.fixNameCrcValues.result=Fixed {0} name CRC32 values for UTF-8 encoding. See file {1} for details. +patch.fixNameCrcValues.fixed=Updated CRC32 value for node ID {0}, name ''{1}'': {2} -> {3}. diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 80cd95e18e..e717157221 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -1646,8 +1646,8 @@ - - + + patch.db-V2.2-Person-2 patch.schemaUpgradeScript.description 0 @@ -1833,4 +1833,28 @@ + + patch.fixNameCrcValues + patch.fixNameCrcValues.description + 0 + 2014 + 2015 + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 900c70e119..841c0fa1ed 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=2014 +version.schema=2015 diff --git a/source/java/org/alfresco/jcr/exporter/JCRDocumentXMLExporter.java b/source/java/org/alfresco/jcr/exporter/JCRDocumentXMLExporter.java index 9c1c7fc049..b97f51765e 100644 --- a/source/java/org/alfresco/jcr/exporter/JCRDocumentXMLExporter.java +++ b/source/java/org/alfresco/jcr/exporter/JCRDocumentXMLExporter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -29,6 +29,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Locale; import javax.jcr.RepositoryException; import javax.jcr.Value; @@ -376,7 +377,15 @@ public class JCRDocumentXMLExporter implements Exporter public void endReference(NodeRef nodeRef) { } - + + public void endValueMLText(NodeRef nodeRef) + { + } + + public void startValueMLText(NodeRef nodeRef, Locale locale) + { + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.view.Exporter#warning(java.lang.String) */ diff --git a/source/java/org/alfresco/jcr/exporter/JCRSystemXMLExporter.java b/source/java/org/alfresco/jcr/exporter/JCRSystemXMLExporter.java index 55906380cc..67b7292c46 100644 --- a/source/java/org/alfresco/jcr/exporter/JCRSystemXMLExporter.java +++ b/source/java/org/alfresco/jcr/exporter/JCRSystemXMLExporter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,6 +26,7 @@ package org.alfresco.jcr.exporter; import java.io.IOException; import java.io.InputStream; +import java.util.Locale; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; @@ -436,7 +437,15 @@ public class JCRSystemXMLExporter implements Exporter public void endReference(NodeRef nodeRef) { } - + + public void endValueMLText(NodeRef nodeRef) + { + } + + public void startValueMLText(NodeRef nodeRef, Locale locale) + { + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.view.Exporter#warning(java.lang.String) */ diff --git a/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java new file mode 100644 index 0000000000..f797183af4 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2005-2009 Alfresco Software Limited. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.admin.patch.impl; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.zip.CRC32; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.ChildAssoc; +import org.alfresco.repo.domain.Node; +import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.hibernate.ChildAssocImpl; +import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.service.cmr.admin.PatchException; +import org.hibernate.SQLQuery; +import org.hibernate.ScrollMode; +import org.hibernate.ScrollableResults; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.type.LongType; +import org.hibernate.type.StringType; +import org.springframework.orm.hibernate3.HibernateCallback; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; + +/** + * Fixes ETWOTWO-1133. + * Checks all CRC values for alf_child_assoc.child_node_name_crc. + * + * @author Derek Hulley + * @since V2.2SP4 + */ +public class FixNameCrcValuesPatch extends AbstractPatch +{ + private static final String MSG_SUCCESS = "patch.fixNameCrcValues.result"; + private static final String MSG_REWRITTEN = "patch.fixNameCrcValues.fixed"; + + private SessionFactory sessionFactory; + private NodeDaoService nodeDaoService; + private QNameDAO qnameDAO; + + public FixNameCrcValuesPatch() + { + } + + public void setSessionFactory(SessionFactory sessionFactory) + { + this.sessionFactory = sessionFactory; + } + + /** + * @param nodeDaoService The service that generates the CRC values + */ + public void setNodeDaoService(NodeDaoService nodeDaoService) + { + this.nodeDaoService = nodeDaoService; + } + + /** + * @param qnameDAO resolved QNames + */ + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + + @Override + protected void checkProperties() + { + super.checkProperties(); + checkPropertyNotNull(sessionFactory, "sessionFactory"); + checkPropertyNotNull(nodeDaoService, "nodeDaoService"); + checkPropertyNotNull(qnameDAO, "qnameDAO"); + } + + @Override + protected String applyInternal() throws Exception + { + // initialise the helper + HibernateHelper helper = new HibernateHelper(); + helper.setSessionFactory(sessionFactory); + + try + { + String msg = helper.fixCrcValues(); + // done + return msg; + } + finally + { + helper.closeWriter(); + } + } + + private class HibernateHelper extends HibernateDaoSupport + { + private File logFile; + private FileChannel channel; + + private HibernateHelper() throws IOException + { + logFile = new File("./FixNameCrcValuesPatch.log"); + // open the file for appending + RandomAccessFile outputFile = new RandomAccessFile(logFile, "rw"); + channel = outputFile.getChannel(); + // move to the end of the file + channel.position(channel.size()); + // add a newline and it's ready + writeLine("").writeLine(""); + writeLine("FixNameCrcValuesPatch executing on " + new Date()); + } + + private HibernateHelper write(Object obj) throws IOException + { + channel.write(ByteBuffer.wrap(obj.toString().getBytes("UTF-8"))); + return this; + } + private HibernateHelper writeLine(Object obj) throws IOException + { + write(obj); + write("\n"); + return this; + } + private void closeWriter() + { + try { channel.close(); } catch (Throwable e) {} + } + + public String fixCrcValues() throws Exception + { + // get the association types to check + @SuppressWarnings("unused") + List childAssocIds = findMismatchedCrcs(); + + int updated = 0; + for (Long childAssocId : childAssocIds) + { + ChildAssoc assoc = (ChildAssoc) getHibernateTemplate().get(ChildAssocImpl.class, childAssocId); + if (assoc == null) + { + // Missing now ... + continue; + } + // Get the old CRC + long oldCrc = assoc.getChildNodeNameCrc(); + // Get the child node + Node childNode = assoc.getChild(); + // Get the name + String childName = (String) nodeDaoService.getNodeProperty(childNode.getId(), ContentModel.PROP_NAME); + if (childName == null) + { + childName = childNode.getUuid(); + } + // Update the CRC + long crc = getCrc(childName); + // Update the assoc + assoc.setChildNodeNameCrc(crc); + // Persist + updated++; + getSession().flush(); + getSession().clear(); + // Record + writeLine(I18NUtil.getMessage(MSG_REWRITTEN, childNode.getId(), childName, oldCrc, crc)); + } + + String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile); + return msg; + } + + @SuppressWarnings("unchecked") + private List findMismatchedCrcs() throws Exception + { + final Long qnameId = qnameDAO.getOrCreateQName(ContentModel.PROP_NAME).getFirst(); + + final List childAssocIds = new ArrayList(1000); + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + SQLQuery query = session + .createSQLQuery( + " SELECT " + + " ca.id AS child_assoc_id," + + " ca.child_node_name_crc AS child_assoc_crc," + + " np.string_value AS node_name," + + " n.uuid as node_uuid" + + " FROM" + + " alf_child_assoc ca" + + " JOIN alf_node n ON (ca.child_node_id = n.id AND ca.child_node_name_crc > 0)" + + " JOIN alf_node_properties np on (np.node_id = n.id AND np.qname_id = :qnameId)" + + ""); + query.setLong("qnameId", qnameId); + query.addScalar("child_assoc_id", new LongType()); + query.addScalar("child_assoc_crc", new LongType()); + query.addScalar("node_name", new StringType()); + query.addScalar("node_uuid", new StringType()); + return query.scroll(ScrollMode.FORWARD_ONLY); + } + }; + ScrollableResults rs = null; + try + { + rs = (ScrollableResults) getHibernateTemplate().execute(callback); + while (rs.next()) + { + Long assocId = (Long) rs.get(0); + Long dbCrc = (Long) rs.get(1); + String name = (String) rs.get(2); + String uuid = (String) rs.get(3); + long utf8Crc = -1L; + if (name != null) + { + utf8Crc = getCrc(name); + } + else + { + utf8Crc = getCrc(uuid); + } + // Check + if (dbCrc != null && utf8Crc == dbCrc.longValue()) + { + // It is a match, so ignore + continue; + } + childAssocIds.add(assocId); + } + } + catch (Throwable e) + { + logger.error("Failed to query for child name CRCs", e); + writeLine("Failed to query for child name CRCs: " + e.getMessage()); + throw new PatchException("Failed to query for child name CRCs", e); + } + finally + { + if (rs != null) + { + try { rs.close(); } catch (Throwable e) { writeLine("Failed to close resultset: " + e.getMessage()); } + } + } + return childAssocIds; + } + + /** + * @param str the name that will be converted to lowercase + * @return the CRC32 calcualted on the lowercase version of the string + */ + private long getCrc(String str) + { + CRC32 crc = new CRC32(); + try + { + crc.update(str.toLowerCase().getBytes("UTF-8")); // https://issues.alfresco.com/jira/browse/ALFCOM-1335 + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("UTF-8 encoding is not supported"); + } + return crc.getValue(); + } + } +} diff --git a/source/java/org/alfresco/repo/exporter/ChainedExporter.java b/source/java/org/alfresco/repo/exporter/ChainedExporter.java index c3a04bb667..5c251d9234 100644 --- a/source/java/org/alfresco/repo/exporter/ChainedExporter.java +++ b/source/java/org/alfresco/repo/exporter/ChainedExporter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,6 +27,7 @@ package org.alfresco.repo.exporter; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; @@ -350,7 +351,23 @@ import org.alfresco.service.namespace.QName; exporter.endReference(nodeRef); } } - + + public void startValueMLText(NodeRef nodeRef, Locale locale) + { + for (Exporter exporter : exporters) + { + exporter.startValueMLText(nodeRef, locale); + } + } + + public void endValueMLText(NodeRef nodeRef) + { + for (Exporter exporter : exporters) + { + exporter.endValueMLText(nodeRef); + } + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.view.Exporter#warning(java.lang.String) */ diff --git a/source/java/org/alfresco/repo/exporter/ExporterComponent.java b/source/java/org/alfresco/repo/exporter/ExporterComponent.java index 4a1a9e99cb..f001d1bd15 100644 --- a/source/java/org/alfresco/repo/exporter/ExporterComponent.java +++ b/source/java/org/alfresco/repo/exporter/ExporterComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,10 +34,12 @@ import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import org.alfresco.model.ContentModel; +import org.alfresco.repo.node.MLPropertyInterceptor; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.PropertyDefinition; @@ -46,6 +48,7 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; +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; @@ -427,7 +430,9 @@ public class ExporterComponent // Export node properties exporter.startProperties(nodeRef); + boolean aware = MLPropertyInterceptor.setMLAware(true); Map properties = nodeService.getProperties(nodeRef); + MLPropertyInterceptor.setMLAware(aware); for (QName property : properties.keySet()) { // filter out properties whose namespace is excluded @@ -459,7 +464,27 @@ public class ExporterComponent } else { - walkProperty(nodeRef, property, value, -1, parameters, exporter); + if (value instanceof MLText) + { + MLText valueMLT = (MLText) value; + Set locales = valueMLT.getLocales(); + for (Locale locale : locales) + { + String localeValue = valueMLT.getValue(locale); + if (localeValue == null) + { + walkProperty(nodeRef, property, localeValue, -1, parameters, exporter); + continue; + } + exporter.startValueMLText(nodeRef, locale); + walkProperty(nodeRef, property, localeValue, -1, parameters, exporter); + exporter.endValueMLText(nodeRef); + } + } + else + { + walkProperty(nodeRef, property, value, -1, parameters, exporter); + } } // end export of property diff --git a/source/java/org/alfresco/repo/exporter/ExporterComponentTest.java b/source/java/org/alfresco/repo/exporter/ExporterComponentTest.java index f472c36116..8a6b66a7a5 100644 --- a/source/java/org/alfresco/repo/exporter/ExporterComponentTest.java +++ b/source/java/org/alfresco/repo/exporter/ExporterComponentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,7 +28,9 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; +import java.util.Locale; +import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ContentData; @@ -96,7 +98,10 @@ public class ExporterComponentTest extends BaseSpringTest InputStream test = getClass().getClassLoader().getResourceAsStream("org/alfresco/repo/importer/importercomponent_test.xml"); InputStreamReader testReader = new InputStreamReader(test, "UTF-8"); importerService.importView(testReader, location, null, null); - System.out.println(NodeStoreInspector.dumpNodeStore((NodeService)applicationContext.getBean("NodeService"), storeRef)); + + dumpNodeStore(Locale.ENGLISH); + dumpNodeStore(Locale.FRENCH); + dumpNodeStore(Locale.GERMAN); // now export location.setPath("/system"); @@ -108,6 +113,13 @@ public class ExporterComponentTest extends BaseSpringTest output.close(); } + private void dumpNodeStore(Locale locale) + { + + System.out.println(locale.getDisplayLanguage() + " LOCALE: "); + I18NUtil.setLocale(locale); + System.out.println(NodeStoreInspector.dumpNodeStore((NodeService) applicationContext.getBean("NodeService"), storeRef)); + } private static class TestProgress implements Exporter @@ -253,6 +265,16 @@ public class ExporterComponentTest extends BaseSpringTest // System.out.println("TestProgress: endReference: " + nodeRef); } + public void endValueMLText(NodeRef nodeRef) + { + System.out.println("TestProgress: end MLValue."); + } + + public void startValueMLText(NodeRef nodeRef, Locale locale) + { + System.out.println("TestProgress: start MLValue for locale: " + locale); + } + } } diff --git a/source/java/org/alfresco/repo/exporter/URLExporter.java b/source/java/org/alfresco/repo/exporter/URLExporter.java index a3b31c0ca2..cdd1236a11 100644 --- a/source/java/org/alfresco/repo/exporter/URLExporter.java +++ b/source/java/org/alfresco/repo/exporter/URLExporter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,6 +25,7 @@ package org.alfresco.repo.exporter; import java.io.InputStream; +import java.util.Locale; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; @@ -276,6 +277,16 @@ import org.alfresco.util.ParameterCheck; exporter.endReference(nodeRef); } + public void startValueMLText(NodeRef nodeRef, Locale locale) + { + exporter.startValueMLText(nodeRef, locale); + } + + public void endValueMLText(NodeRef nodeRef) + { + exporter.endValueMLText(nodeRef); + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.view.Exporter#warning(java.lang.String) */ diff --git a/source/java/org/alfresco/repo/exporter/ViewXMLExporter.java b/source/java/org/alfresco/repo/exporter/ViewXMLExporter.java index 1dfa11eec8..f886768840 100644 --- a/source/java/org/alfresco/repo/exporter/ViewXMLExporter.java +++ b/source/java/org/alfresco/repo/exporter/ViewXMLExporter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,6 +26,7 @@ package org.alfresco.repo.exporter; import java.io.InputStream; import java.util.List; +import java.util.Locale; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -74,6 +75,8 @@ import org.xml.sax.helpers.AttributesImpl; private static final String EXPORTEDDATE_LOCALNAME = "exportDate"; private static final String EXPORTERVERSION_LOCALNAME = "exporterVersion"; private static final String EXPORTOF_LOCALNAME = "exportOf"; + private static final String MLVALUE_LOCALNAME = "mlvalue"; + private static final String LOCALE_LOCALNAME = "locale"; private static final String ACL_LOCALNAME = "acl"; private static final String ACE_LOCALNAME = "ace"; private static final String ACCESS_LOCALNAME = "access"; @@ -106,6 +109,8 @@ import org.xml.sax.helpers.AttributesImpl; private static QName REFERENCE_QNAME; private static QName PATHREF_QNAME; private static QName NODEREF_QNAME; + private static QName LOCALE_QNAME; + private static QName MLVALUE_QNAME; private static final AttributesImpl EMPTY_ATTRIBUTES = new AttributesImpl(); // Service dependencies @@ -164,6 +169,9 @@ import org.xml.sax.helpers.AttributesImpl; REFERENCE_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, REFERENCE_LOCALNAME, namespaceService); PATHREF_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, PATHREF_LOCALNAME, namespaceService); NODEREF_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, NODEREF_LOCALNAME, namespaceService); + LOCALE_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, LOCALE_LOCALNAME, namespaceService); + MLVALUE_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, MLVALUE_LOCALNAME, namespaceService); + } @@ -718,7 +726,34 @@ import org.xml.sax.helpers.AttributesImpl; throw new ExporterException("Failed to process end reference", e); } } - + + public void startValueMLText(NodeRef nodeRef, Locale locale) + { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_PREFIX, LOCALE_LOCALNAME, LOCALE_QNAME.toPrefixString(), null, locale.toString()); + try + { + contentHandler.startElement(NamespaceService.REPOSITORY_VIEW_PREFIX, MLVALUE_LOCALNAME, MLVALUE_QNAME.toPrefixString(), attrs); + } + catch (SAXException e) + { + throw new ExporterException("Failed to process start mlvalue", e); + } + } + + public void endValueMLText(NodeRef nodeRef) + { + try + { + contentHandler.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, MLVALUE_LOCALNAME, MLVALUE_QNAME.toPrefixString()); + } + catch (SAXException e) + { + throw new ExporterException("Failed to process end mltext", e); + } + + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.view.Exporter#warning(java.lang.String) */ diff --git a/source/java/org/alfresco/repo/importer/ImporterComponent.java b/source/java/org/alfresco/repo/importer/ImporterComponent.java index 4309b2386c..9abda6caaa 100644 --- a/source/java/org/alfresco/repo/importer/ImporterComponent.java +++ b/source/java/org/alfresco/repo/importer/ImporterComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -945,7 +945,7 @@ public class ImporterComponent if (value instanceof Collection) { List boundCollection = new ArrayList(); - for (String collectionValue : (Collection)value) + for (Serializable collectionValue : (Collection)value) { Serializable objValue = bindValue(context, property, valueDataType, collectionValue); boundCollection.add(objValue); @@ -954,7 +954,7 @@ public class ImporterComponent } else { - value = bindValue(context, property, valueDataType, (String)value); + value = bindValue(context, property, valueDataType, value); } // choose to provide property on node creation or at end of import for lazy binding @@ -1002,19 +1002,22 @@ public class ImporterComponent * @param value string form of value * @return the bound value */ - private Serializable bindValue(ImportNode context, QName property, DataTypeDefinition valueType, String value) + private Serializable bindValue(ImportNode context, QName property, DataTypeDefinition valueType, Serializable value) { Serializable objValue = null; if (value != null && valueType != null) { - String strValue = bindPlaceHolder(value, binding); + if (value instanceof String) + { + value = bindPlaceHolder(value.toString(), binding); + } if ((valueType.getName().equals(DataTypeDefinition.NODE_REF) || valueType.getName().equals(DataTypeDefinition.CATEGORY))) { - objValue = strValue; + objValue = value; } else { - objValue = (Serializable)DefaultTypeConverter.INSTANCE.convert(valueType, strValue); + objValue = (Serializable) DefaultTypeConverter.INSTANCE.convert(valueType, value); } } diff --git a/source/java/org/alfresco/repo/importer/importercomponent_test.xml b/source/java/org/alfresco/repo/importer/importercomponent_test.xml index eb794f2d37..f7837d4202 100644 --- a/source/java/org/alfresco/repo/importer/importercomponent_test.xml +++ b/source/java/org/alfresco/repo/importer/importercomponent_test.xml @@ -77,11 +77,32 @@ Some content contentUrl=classpath:org/alfresco/repo/importer/importercomponent_testfile.txt|mimetype=text|size=|encoding= + + + + + + + ML Text + + FR_TITLE + GE_TITLE + ENG_TITLE + + + FR_DESCRIPTION + GE_DESCRIPTION + ENG_DESCRIPTION + + + + + diff --git a/source/java/org/alfresco/repo/importer/view/NodeContext.java b/source/java/org/alfresco/repo/importer/view/NodeContext.java index 0bdf792ad2..f0e622cb27 100644 --- a/source/java/org/alfresco/repo/importer/view/NodeContext.java +++ b/source/java/org/alfresco/repo/importer/view/NodeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -247,7 +247,7 @@ public class NodeContext extends ElementContext * @param property the property name * @param value the property value */ - public void addProperty(QName property, String value) + public void addProperty(QName property, Serializable value) { // Process "special" properties // TODO: Make this configurable... @@ -256,7 +256,7 @@ public class NodeContext extends ElementContext // Process Alfresco UUID if (uuid == null && propDef != null && propDef.getName().equals(ContentModel.PROP_NODE_UUID)) { - uuid = value; + uuid = value.toString(); } // Do not import properties of sys:referenceable or cm:versionable diff --git a/source/java/org/alfresco/repo/importer/view/ViewParser.java b/source/java/org/alfresco/repo/importer/view/ViewParser.java index b2ac1c3101..8454c73eaa 100644 --- a/source/java/org/alfresco/repo/importer/view/ViewParser.java +++ b/source/java/org/alfresco/repo/importer/view/ViewParser.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,7 +26,9 @@ package org.alfresco.repo.importer.view; import java.io.IOException; import java.io.Reader; +import java.io.Serializable; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.Stack; @@ -35,11 +37,14 @@ import org.alfresco.repo.importer.Importer; import org.alfresco.repo.importer.Parser; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.AssociationDefinition; +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.dictionary.TypeDefinition; +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.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.view.ImporterException; import org.alfresco.service.namespace.NamespaceService; @@ -71,6 +76,7 @@ public class ViewParser implements Parser private static final String VIEW_IDREF_ATTR = "idref"; private static final String VIEW_PATHREF_ATTR = "pathref"; private static final String VIEW_NODEREF_ATTR = "noderef"; + private static final String VIEW_LOCALE_ATTR = "locale"; private static final QName VIEW_METADATA = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "metadata"); private static final QName VIEW_VALUE_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "value"); private static final QName VIEW_VALUES_QNAME = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "values"); @@ -82,7 +88,7 @@ public class ViewParser implements Parser private static final QName VIEW_AUTHORITY = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "authority"); private static final QName VIEW_PERMISSION = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "permission"); private static final QName VIEW_REFERENCE = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "reference"); - + private static final QName VIEW_ML_VALUE = QName.createQName(NamespaceService.REPOSITORY_VIEW_1_0_URI, "mlvalue"); // XML Pull Parser Factory private XmlPullParserFactory factory; @@ -670,6 +676,7 @@ public class ViewParser implements Parser { // Extract collection, if specified boolean isCollection = false; + boolean isMLProperty = false; if (eventType == XmlPullParser.START_TAG) { QName name = getName(xpp); @@ -683,6 +690,66 @@ public class ViewParser implements Parser eventType = xpp.next(); } } + else if (name.equals(VIEW_ML_VALUE)) + { + isMLProperty = true; + } + } + + // Extract ML value + + if (isMLProperty) + { + if (logger.isDebugEnabled()) + { + logger.debug("Start parsing MLValue for property: " + propertyName); + } + value = ""; + String locale = ""; + node.addDatatype(propertyName, dictionaryService.getDataType(DataTypeDefinition.MLTEXT)); + MLText mlText = new MLText(); + while (isMLProperty) + { + isMLProperty = false; + + locale = xpp.getAttributeValue(NamespaceService.REPOSITORY_VIEW_1_0_URI, VIEW_LOCALE_ATTR); + eventType = xpp.next(); + if (eventType == XmlPullParser.TEXT) + { + value = xpp.getText(); + eventType = xpp.next(); + } + if (eventType == XmlPullParser.END_TAG) + { + if (logger.isDebugEnabled()) + { + logger.debug("Found ML entry: " + locale + "=" + value); + } + mlText.addValue(DefaultTypeConverter.INSTANCE.convert(Locale.class, locale), value); + + eventType = xpp.next(); + if (eventType == XmlPullParser.TEXT) + { + eventType = xpp.next(); + } + } + + if (eventType == XmlPullParser.START_TAG) + { + QName name = getName(xpp); + if (name.equals(VIEW_ML_VALUE)) + { + isMLProperty = true; + } + } + } + + if (logger.isDebugEnabled()) + { + logger.debug("End parsing MLValue for property: " + propertyName); + } + node.addProperty(propertyName, mlText); + } // Extract decorated value diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java index 981f0951c6..90869cdb72 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java @@ -29,12 +29,14 @@ import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import javax.transaction.UserTransaction; import junit.framework.TestCase; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.i18n.I18NUtil; import org.alfresco.model.ContentModel; import org.alfresco.repo.dictionary.DictionaryDAO; import org.alfresco.repo.dictionary.M2Model; @@ -44,6 +46,7 @@ import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileFolderServiceType; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.ContentReader; @@ -651,4 +654,14 @@ public class FileFolderServiceImplTest extends TestCase assertNotNull("Long filename not found", fileNodeRef); assertEquals(fileInfo.getNodeRef(), fileNodeRef); } + + /** + * Validates ACT-7225 + */ + public void testGetType() throws Exception + { + I18NUtil.setContentLocale(Locale.CANADA); + FileFolderServiceType type = fileFolderService.getType(ContentModel.TYPE_FOLDER); + assertEquals("Type incorrect for folder", FileFolderServiceType.FOLDER, type); + } } diff --git a/source/java/org/alfresco/repo/model/filefolder/MLTranslationInterceptor.java b/source/java/org/alfresco/repo/model/filefolder/MLTranslationInterceptor.java index 9e195545ff..e90f4fc4fa 100644 --- a/source/java/org/alfresco/repo/model/filefolder/MLTranslationInterceptor.java +++ b/source/java/org/alfresco/repo/model/filefolder/MLTranslationInterceptor.java @@ -91,6 +91,7 @@ public class MLTranslationInterceptor implements MethodInterceptor METHOD_NAMES_OTHER.add("delete"); METHOD_NAMES_OTHER.add("getReader"); METHOD_NAMES_OTHER.add("getWriter"); + METHOD_NAMES_OTHER.add("getType"); } private static Log logger = LogFactory.getLog(MLTranslationInterceptor.class); diff --git a/source/java/org/alfresco/service/cmr/view/Exporter.java b/source/java/org/alfresco/service/cmr/view/Exporter.java index 5b559f5dfe..b78ea3a51c 100644 --- a/source/java/org/alfresco/service/cmr/view/Exporter.java +++ b/source/java/org/alfresco/service/cmr/view/Exporter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,6 +25,7 @@ package org.alfresco.service.cmr.view; import java.io.InputStream; +import java.util.Locale; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; @@ -178,6 +179,21 @@ public interface Exporter */ public void startValueCollection(NodeRef nodeRef, QName property); + /** + * Start export MLText + * + * @param nodeRef the node reference + * @param locale + */ + public void startValueMLText(NodeRef nodeRef, Locale locale); + + /** + * End export MLText + * + * @param nodeRef + */ + public void endValueMLText(NodeRef nodeRef); + /** * Export property value * diff --git a/source/java/org/alfresco/tools/Export.java b/source/java/org/alfresco/tools/Export.java index 748d9cc269..2d3e7d9199 100644 --- a/source/java/org/alfresco/tools/Export.java +++ b/source/java/org/alfresco/tools/Export.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,6 +26,7 @@ package org.alfresco.tools; import java.io.File; import java.io.InputStream; +import java.util.Locale; import org.alfresco.repo.exporter.ACPExportPackageHandler; import org.alfresco.repo.exporter.FileExportPackageHandler; @@ -645,6 +646,14 @@ public final class Export extends Tool public void endReference(NodeRef nodeRef) { } + + public void endValueMLText(NodeRef nodeRef) + { + } + + public void startValueMLText(NodeRef nodeRef, Locale locale) + { + } } }