Merge 1.4 to HEAD

svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@4351 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@4352 .
   svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@4353 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@4354 .
   svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@4354 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V1.4@4362 .


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4657 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2006-12-19 14:36:46 +00:00
parent 488450a988
commit 760cb0fe77
20 changed files with 332 additions and 148 deletions

View File

@@ -80,7 +80,7 @@ public interface ContentModel
static final QName PROP_SYS_VERSION_BUILD = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionBuild");
static final QName PROP_SYS_VERSION_SCHEMA = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionSchema");
static final QName PROP_SYS_VERSION_EDITION = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionEdition");
static final QName PROP_SYS_VERSION_PROPERTIES = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionProperties");
//
// Content Model Definitions

View File

@@ -18,31 +18,28 @@ package org.alfresco.repo.admin;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.node.index.FullIndexRecoveryComponent.RecoveryMode;
import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
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.repo.transaction.TransactionUtil;
import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.InvalidStoreRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.LimitBy;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.AbstractLifecycleBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -82,17 +79,16 @@ public class ConfigurationChecker extends AbstractLifecycleBean
private boolean strict;
private RecoveryMode indexRecoveryMode;
private String dirRoot;
private boolean checkAllContent;
private AuthenticationComponent authenticationComponent;
private DictionaryService dictionaryService;
private ImporterBootstrap systemBootstrap;
private TransactionService transactionService;
private NamespaceService namespaceService;
private NodeService nodeService;
private SearchService searchService;
private ContentService contentService;
public ConfigurationChecker()
{
this.checkAllContent = false;
}
@Override
@@ -101,7 +97,6 @@ public class ConfigurationChecker extends AbstractLifecycleBean
StringBuilder sb = new StringBuilder(50);
sb.append("ConfigurationChecker")
.append("[indexRecoveryMode=").append(indexRecoveryMode)
.append(", checkAllContent=").append(checkAllContent)
.append("]");
return sb.toString();
}
@@ -119,16 +114,6 @@ public class ConfigurationChecker extends AbstractLifecycleBean
this.strict = strict;
}
/**
* @param checkAllContent <code>true</code> to get all content URLs when checking for
* missing content, or <code>false</code> to just do a quick sanity check against
* the content store.
*/
public void setCheckAllContent(boolean checkAllContent)
{
this.checkAllContent = checkAllContent;
}
/**
* Set the index recovery mode. If this is
* {@link org.alfresco.repo.node.index.FullIndexRecoveryComponent.RecoveryMode#VALIDATE FULL}
@@ -147,14 +132,19 @@ public class ConfigurationChecker extends AbstractLifecycleBean
this.dirRoot = dirRoot;
}
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
public void setSystemBootstrap(ImporterBootstrap systemBootstrap)
{
this.authenticationComponent = authenticationComponent;
this.systemBootstrap = systemBootstrap;
}
public void setDictionaryService(DictionaryService dictionaryService)
public void setTransactionService(TransactionService transactionService)
{
this.dictionaryService = dictionaryService;
this.transactionService = transactionService;
}
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
public void setNodeService(NodeService nodeService)
@@ -175,16 +165,15 @@ public class ConfigurationChecker extends AbstractLifecycleBean
@Override
protected void onBootstrap(ApplicationEvent event)
{
// authenticate
try
TransactionWork<Object> checkWork = new TransactionWork<Object>()
{
authenticationComponent.setSystemUserAsCurrentUser();
check();
}
finally
{
authenticationComponent.clearCurrentSecurityContext();
}
public Object doWork() throws Exception
{
check();
return null;
}
};
TransactionUtil.executeInUserTransaction(transactionService, checkWork);
}
/**
@@ -211,7 +200,6 @@ public class ConfigurationChecker extends AbstractLifecycleBean
// get all root nodes from the NodeService, i.e. database
List<StoreRef> storeRefs = nodeService.getStores();
List<StoreRef> missingIndexStoreRefs = new ArrayList<StoreRef>(0);
List<StoreRef> missingContentStoreRefs = new ArrayList<StoreRef>(0);
for (StoreRef storeRef : storeRefs)
{
NodeRef rootNodeRef = null;
@@ -267,81 +255,23 @@ public class ConfigurationChecker extends AbstractLifecycleBean
throw new AlfrescoRuntimeException(msg);
}
}
// select a content property
QName contentPropertyQName = null;
Collection<QName> typeQNames = dictionaryService.getAllTypes();
/* BREAK POINT */ contentPropertyFound:
for (QName typeQName : typeQNames)
}
// check for the system version properties content snippet
boolean versionPropertiesContentAvailable = true;
NodeRef descriptorNodeRef = getSystemDescriptor();
if (descriptorNodeRef != null)
{
// get the version properties
ContentReader reader = contentService.getReader(
descriptorNodeRef,
ContentModel.PROP_SYS_VERSION_PROPERTIES);
if (reader != null && !reader.exists())
{
TypeDefinition classDef = dictionaryService.getType(typeQName);
Map<QName, PropertyDefinition> propertyDefs = classDef.getProperties();
for (PropertyDefinition propertyDef : propertyDefs.values())
{
if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT))
{
continue;
}
contentPropertyQName = propertyDef.getName();
break contentPropertyFound;
}
}
// do a search for nodes with content
if (contentPropertyQName != null)
{
String attributeName = "\\@" + LuceneQueryParser.escape(contentPropertyQName.toString());
SearchParameters sp = new SearchParameters();
sp.addStore(storeRef);
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery(attributeName + ":*");
if (!checkAllContent)
{
sp.setLimit(1);
sp.setLimitBy(LimitBy.FINAL_SIZE);
}
ResultSet results = null;
try
{
results = searchService.query(sp);
// iterate and attempt to get the content
for (ResultSetRow row : results)
{
NodeRef nodeRef = row.getNodeRef();
ContentReader reader = contentService.getReader(nodeRef, contentPropertyQName);
if (reader == null)
{
// content not written
continue;
}
else if (reader.exists())
{
// the data is present in the content store
}
else
{
// URL is missing
missingContentStoreRefs.add(storeRef);
// debug
if (logger.isDebugEnabled())
{
logger.debug("Content missing from store: \n" +
" store: " + storeRef + "\n" +
" content: " + reader);
}
}
// break out if necessary
if (!checkAllContent)
{
break;
}
}
}
finally
{
try { results.close(); } catch (Throwable e) {}
}
// the property is there, but the content is not
versionPropertiesContentAvailable = false;
}
}
// check for missing indexes
int missingStoreIndexes = missingIndexStoreRefs.size();
if (missingStoreIndexes > 0)
@@ -352,14 +282,13 @@ public class ConfigurationChecker extends AbstractLifecycleBean
logger.info(msgRecover);
}
// check for missing content
int missingStoreContent = missingContentStoreRefs.size();
if (missingStoreContent > 0)
if (!versionPropertiesContentAvailable)
{
String msg = I18NUtil.getMessage(ERR_MISSING_CONTENT, missingStoreContent);
String msg = I18NUtil.getMessage(ERR_MISSING_CONTENT);
logger.error(msg);
}
// handle either content or indexes missing
if (missingStoreIndexes > 0 || missingStoreContent > 0)
if (missingStoreIndexes > 0 || !versionPropertiesContentAvailable)
{
String msg = I18NUtil.getMessage(ERR_FIX_DIR_ROOT, dirRootFile);
logger.error(msg);
@@ -376,6 +305,29 @@ public class ConfigurationChecker extends AbstractLifecycleBean
}
}
}
/**
* @return Returns the system descriptor node or null
*/
public NodeRef getSystemDescriptor()
{
StoreRef systemStoreRef = systemBootstrap.getStoreRef();
List<NodeRef> nodeRefs = null;
if (nodeService.exists(systemStoreRef))
{
Properties systemProperties = systemBootstrap.getConfiguration();
String path = systemProperties.getProperty("system.descriptor.current.childname");
String searchPath = "/" + path;
NodeRef rootNodeRef = nodeService.getRootNode(systemStoreRef);
nodeRefs = searchService.selectNodes(rootNodeRef, searchPath, null, namespaceService, false);
if (nodeRefs.size() > 0)
{
NodeRef descriptorNodeRef = nodeRefs.get(0);
return descriptorNodeRef;
}
}
return null;
}
@Override
protected void onShutdown(ApplicationEvent event)

View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2005 Alfresco, Inc.
*
* Licensed under the Mozilla Public License version 1.1
* with a permitted attribution clause. You may obtain a
* copy of the License at
*
* http://www.alfresco.org/legal/license.txt
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the
* License.
*/
package org.alfresco.repo.admin.patch.impl;
import java.io.InputStream;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.admin.ConfigurationChecker;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.admin.PatchException;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
/**
* Ensures that the required content snippet is added to the system descriptor
* to enable robust checking of the content store by the configuration checker.
*
* @author Derek Hulley
*/
public class SystemDescriptorContentPatch extends AbstractPatch
{
private static final String MSG_SUCCESS = "patch.systemDescriptorContent.result";
private static final String ERR_NO_VERSION_PROPERTIES = "patch.systemDescriptorContent.err.no_version_properties";
private static final String ERR_NO_SYSTEM_DESCRIPTOR = "patch.systemDescriptorContent.err.no_descriptor";
private ConfigurationChecker configurationChecker;
private ContentService contentService;
public SystemDescriptorContentPatch()
{
}
public void setConfigurationChecker(ConfigurationChecker configurationChecker)
{
this.configurationChecker = configurationChecker;
}
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
@Override
protected void checkProperties()
{
super.checkProperties();
checkPropertyNotNull(configurationChecker, "configurationChecker");
checkPropertyNotNull(contentService, "contentService");
}
@Override
protected String applyInternal() throws Exception
{
InputStream is = null;
try
{
// get the version.properties
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:alfresco/version.properties");
if (!resource.exists())
{
throw new PatchException(ERR_NO_VERSION_PROPERTIES);
}
is = resource.getInputStream();
// get the system descriptor
NodeRef descriptorNodeRef = configurationChecker.getSystemDescriptor();
if (descriptorNodeRef == null)
{
throw new PatchException(ERR_NO_SYSTEM_DESCRIPTOR);
}
// get the writer
ContentWriter writer = contentService.getWriter(descriptorNodeRef, ContentModel.PROP_SYS_VERSION_PROPERTIES, true);
// upload
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.setEncoding("UTF8");
writer.putContent(is);
// done
String msg = I18NUtil.getMessage(MSG_SUCCESS);
return msg;
}
finally
{
if (is != null)
{
try { is.close(); } catch (Throwable e) {}
}
}
}
}

View File

@@ -329,11 +329,19 @@ public class RoutingContentService implements ContentService
public ContentWriter getWriter(NodeRef nodeRef, QName propertyQName, boolean update)
{
// TODO: Choose the store to write to at runtime
if (nodeRef == null)
{
// for this case, we just give back a valid URL into the content store
ContentWriter writer = store.getWriter(null, null);
// done
return writer;
}
// check for an existing URL - the get of the reader will perform type checking
ContentReader existingContentReader = getReader(nodeRef, propertyQName, false);
// TODO: Choose the store to write to at runtime
// get the content using the (potentially) existing content - the new content
// can be wherever the store decides.
ContentWriter writer = store.getWriter(existingContentReader, null);

View File

@@ -153,6 +153,29 @@ public class RoutingContentServiceTest extends TestCase
assertFalse(getUserTransaction() == getUserTransaction()); // ensure txn instances aren't shared
}
/**
* Check that a valid writer into the content store can be retrieved and used.
*/
public void testSimpleNonTempWriter() throws Exception
{
ContentWriter writer = contentService.getWriter(null, null, false);
assertNotNull("Writer should not be null", writer);
assertNotNull("Content URL should not be null", writer.getContentUrl());
// write some content
writer.putContent(SOME_CONTENT);
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.setEncoding("UTF8");
// set the content property manually
nodeService.setProperty(contentNodeRef, ContentModel.PROP_CONTENT, writer.getContentData());
// get the reader
ContentReader reader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT);
assertNotNull("Reader should not be null", reader);
assertNotNull("Content URL should not be null", reader.getContentUrl());
}
/**
* Checks that the URL, mimetype and encoding are automatically set on the readers
* and writers

View File

@@ -166,6 +166,9 @@ public class RepositoryExporterComponent implements RepositoryExporterService
handle.mimeType = exportHandle.mimeType;
handle.exportFile = repoExportFile;
repoExportHandles.add(handle);
// delete temporary export file
exportHandle.exportFile.delete();
}
return repoExportHandles.toArray(new RepositoryExportHandle[repoExportHandles.size()]);
@@ -326,7 +329,8 @@ public class RepositoryExporterComponent implements RepositoryExporterService
public FileExportHandle exportStore(ExporterCrawlerParameters exportParameters, String packageName, Exporter progress)
{
// create a temporary file to hold the acp export
File tempFile = TempFileProvider.createTempFile("repoExp" + packageName, "." + ACPExportPackageHandler.ACP_EXTENSION);
File systemTempDir = TempFileProvider.getSystemTempDir();
File tempFile = TempFileProvider.createTempFile("repoExp" + packageName, "." + ACPExportPackageHandler.ACP_EXTENSION, systemTempDir);
// create acp export handler around the temp file
File dataFile = new File(packageName);
@@ -361,7 +365,8 @@ public class RepositoryExporterComponent implements RepositoryExporterService
public FileExportHandle exportSystem(String packageName)
{
// create a temporary file to hold the system info export
File tempFile = TempFileProvider.createTempFile("repoExpSystemInfo", ".xml");
File systemTempDir = TempFileProvider.getSystemTempDir();
File tempFile = TempFileProvider.createTempFile("repoExpSystemInfo", ".xml", systemTempDir);
try
{

View File

@@ -489,22 +489,22 @@ public class PermissionServiceTest extends AbstractPermissionTest
QName ownable = QName.createQName("cm", "ownable", namespacePrefixResolver);
Set<String> answer = permissionService.getSettablePermissions(rootNodeRef);
assertEquals(42, answer.size());
assertEquals(36, answer.size());
nodeService.addAspect(rootNodeRef, ownable, null);
answer = permissionService.getSettablePermissions(rootNodeRef);
assertEquals(42, answer.size());
assertEquals(36, answer.size());
nodeService.removeAspect(rootNodeRef, ownable);
answer = permissionService.getSettablePermissions(rootNodeRef);
assertEquals(42, answer.size());
assertEquals(36, answer.size());
}
public void testSimplePermissionOnRoot()
{
runAs("andy");
assertEquals(42, permissionService.getPermissions(rootNodeRef).size());
assertEquals(36, permissionService.getPermissions(rootNodeRef).size());
assertEquals(0, countGranted(permissionService.getPermissions(rootNodeRef)));
assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size());
@@ -517,7 +517,7 @@ public class PermissionServiceTest extends AbstractPermissionTest
assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size());
runAs("andy");
assertEquals(42, permissionService.getPermissions(rootNodeRef).size());
assertEquals(36, permissionService.getPermissions(rootNodeRef).size());
assertEquals(2, countGranted(permissionService.getPermissions(rootNodeRef)));
assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED);
@@ -633,7 +633,7 @@ public class PermissionServiceTest extends AbstractPermissionTest
permissionService.setPermission(allowAndyRead);
runAs("andy");
assertEquals(42, permissionService.getPermissions(rootNodeRef).size());
assertEquals(36, permissionService.getPermissions(rootNodeRef).size());
assertEquals(7, countGranted(permissionService.getPermissions(rootNodeRef)));
assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size());

View File

@@ -433,7 +433,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
//
QName typeName = nodeService.getType(nodeRef);
Set<PermissionReference> permissions = getAllPermissions(typeName);
Set<PermissionReference> permissions = getAllPermissionsImpl(typeName, exposedOnly);
mergeGeneralAspectPermissions(permissions, exposedOnly);
// Add non mandatory aspects...
Set<QName> defaultAspects = new HashSet<QName>();

View File

@@ -32,6 +32,8 @@ import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.repository.TemplateProcessor;
import org.apache.log4j.Logger;
import bsh.This;
import freemarker.cache.MruCacheStorage;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
@@ -70,6 +72,9 @@ public class FreeMarkerProcessor implements TemplateProcessor
/** The Content Service to use */
private ContentService contentService;
/** Template encoding */
private String defaultEncoding;
/**
* Set the node service
*
@@ -90,6 +95,16 @@ public class FreeMarkerProcessor implements TemplateProcessor
this.contentService = contentService;
}
/**
* Set the default template encoding
*
* @param defaultEncoding the default encoding
*/
public void setDefaultEncoding(String defaultEncoding)
{
this.defaultEncoding = defaultEncoding;
}
/**
* Get the FreeMarker configuration for this instance
*
@@ -111,6 +126,12 @@ public class FreeMarkerProcessor implements TemplateProcessor
// rethrow any exception so we can deal with them
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// set default template encoding
if (defaultEncoding != null)
{
config.setDefaultEncoding(defaultEncoding);
}
return config;
}
@@ -140,6 +161,12 @@ public class FreeMarkerProcessor implements TemplateProcessor
// rethrow any exception so we can deal with them
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// set default template encoding
if (defaultEncoding != null)
{
config.setDefaultEncoding(defaultEncoding);
}
return config;
}

View File

@@ -74,8 +74,12 @@ public interface ContentService
* regardless of the state of the written binary data. If the flag is on, then the node
* property will be updated on the same thread as the code that closed the write
* channel.
* <p>
* If no node is supplied, then the writer will provide a stream into the backing content
* store, but will not be associated with any new or previous content.
*
* @param nodeRef a reference to a node having a content property
* @param nodeRef a reference to a node having a content property, or <tt>null</tt>
* to just get a valid writer into a backing content store.
* @param propertyQName the name of the property, which must be of type <b>content</b>
* @param update true if the property must be updated atomically when the content write
* stream is closed (attaches a listener to the stream); false if the client code