Merged DEV/3.1_ENTERPRISE_ONLY to HEAD

12465: Supporting changes for enterprise-only monitoring code.

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@12495 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2008-12-18 15:26:23 +00:00
parent d20db6284c
commit 6b3d327f64
29 changed files with 1123 additions and 83 deletions

View File

@@ -40,7 +40,7 @@ import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Abstract base class that provides a set of tests for implementations
@@ -54,7 +54,7 @@ import org.springframework.context.ApplicationContext;
*/
public abstract class AbstractReadOnlyContentStoreTest extends TestCase
{
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
protected static final ConfigurableApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private static Log logger = LogFactory.getLog(AbstractReadOnlyContentStoreTest.class);

View File

@@ -69,6 +69,10 @@ import org.alfresco.util.Pair;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
/**
@@ -77,7 +81,7 @@ import org.apache.commons.logging.LogFactory;
*
* @author Derek Hulley
*/
public class RoutingContentService implements ContentService
public class RoutingContentService implements ContentService, ApplicationContextAware
{
private static Log logger = LogFactory.getLog(RoutingContentService.class);
@@ -85,6 +89,7 @@ public class RoutingContentService implements ContentService
private NodeService nodeService;
private AVMService avmService;
private RetryingTransactionHelper transactionHelper;
private ApplicationContext applicationContext;
/** a registry of all available content transformers */
private ContentTransformerRegistry transformerRegistry;
@@ -105,14 +110,6 @@ public class RoutingContentService implements ContentService
ClassPolicyDelegate<ContentServicePolicies.OnContentUpdatePolicy> onContentUpdateDelegate;
ClassPolicyDelegate<ContentServicePolicies.OnContentReadPolicy> onContentReadDelegate;
/**
* Default constructor sets up a temporary store
*/
public RoutingContentService()
{
this.tempStore = new FileContentStore(TempFileProvider.getTempDir().getAbsolutePath());
}
/**
* @deprecated Replaced by {@link #setRetryingTransactionHelper(RetryingTransactionHelper)}
*/
@@ -161,11 +158,24 @@ public class RoutingContentService implements ContentService
this.imageMagickContentTransformer = imageMagickContentTransformer;
}
/* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
/**
* Service initialise
*/
public void init()
{
// Set up a temporary store
this.tempStore = new FileContentStore((ConfigurableApplicationContext) this.applicationContext,
TempFileProvider.getTempDir().getAbsolutePath());
// Bind on update properties behaviour
this.policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"),

View File

@@ -65,13 +65,13 @@ public class RoutingContentStoreTest extends AbstractWritableContentStoreTest
File tempDir = TempFileProvider.getTempDir();
// Create a subdirectory for A
File storeADir = new File(tempDir, "A");
storeA = new FileContentStore(storeADir);
storeA = new FileContentStore(ctx, storeADir);
// Create a subdirectory for B
File storeBDir = new File(tempDir, "B");
storeB = new FileContentStore(storeBDir);
storeB = new FileContentStore(ctx, storeBDir);
// Create a subdirectory for C
File storeCDir = new File(tempDir, "C");
storeC = new DumbReadOnlyFileStore(new FileContentStore(storeCDir));
storeC = new DumbReadOnlyFileStore(new FileContentStore(ctx, storeCDir));
// No subdirectory for D
storeD = new SupportsNoUrlFormatStore();
// Create the routing store

View File

@@ -36,18 +36,23 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.Tenant;
import org.alfresco.repo.tenant.TenantDeployer;
import org.alfresco.repo.tenant.TenantService;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Content Store that supports tenant routing, if multi-tenancy is enabled.
*
* Note: Need to initialise before the dictionary service, in the case that models are dynamically loaded for the tenant.
*/
public class TenantRoutingFileContentStore extends AbstractRoutingContentStore implements TenantDeployer
public class TenantRoutingFileContentStore extends AbstractRoutingContentStore implements TenantDeployer, ApplicationContextAware
{
Map<String, FileContentStore> tenantFileStores = new HashMap<String, FileContentStore>();
private String defaultRootDirectory;
private TenantService tenantService;
private ApplicationContext applicationContext;
public void setDefaultRootDir(String defaultRootDirectory)
@@ -59,6 +64,16 @@ public class TenantRoutingFileContentStore extends AbstractRoutingContentStore i
{
this.tenantService = tenantService;
}
/*
* (non-Javadoc)
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
* ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
protected ContentStore selectWriteStore(ContentContext ctx)
{
@@ -114,7 +129,8 @@ public class TenantRoutingFileContentStore extends AbstractRoutingContentStore i
tenantDomain = tenant.getTenantDomain();
}
putTenantFileStore(tenantDomain, new FileContentStore(new File(rootDir)));
putTenantFileStore(tenantDomain, new FileContentStore((ConfigurableApplicationContext) this.applicationContext,
new File(rootDir)));
}
public void destroy()

View File

@@ -29,6 +29,8 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import junit.framework.TestCase;
import org.alfresco.repo.avm.AVMNodeDAO;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.filestore.FileContentStore;
@@ -42,9 +44,7 @@ import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.TempFileProvider;
import org.springframework.context.ApplicationContext;
import junit.framework.TestCase;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @see org.alfresco.repo.content.cleanup.ContentStoreCleaner
@@ -53,7 +53,7 @@ import junit.framework.TestCase;
*/
public class ContentStoreCleanerTest extends TestCase
{
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private static ConfigurableApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
private ContentStoreCleaner cleaner;
private ContentStore store;
@@ -71,7 +71,7 @@ public class ContentStoreCleanerTest extends TestCase
ContentUrlDAO contentUrlDAO = (ContentUrlDAO) ctx.getBean("contentUrlDAO");
// we need a store
store = new FileContentStore(TempFileProvider.getTempDir().getAbsolutePath());
store = new FileContentStore(ctx, TempFileProvider.getTempDir().getAbsolutePath());
// and a listener
listener = new DummyCleanerListener();
// initialise record of deleted URLs

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
* Copyright (C) 2005-2008 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
@@ -18,7 +18,7 @@
* 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
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
@@ -43,6 +43,10 @@ import org.alfresco.util.GUID;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
/**
* Provides a store of node content directly to the file system. The writers
@@ -53,7 +57,7 @@ import org.apache.commons.logging.LogFactory;
*
* @author Derek Hulley
*/
public class FileContentStore extends AbstractContentStore
public class FileContentStore extends AbstractContentStore implements ApplicationListener
{
/**
* <b>store</b> is the new prefix for file content URLs
@@ -69,21 +73,24 @@ public class FileContentStore extends AbstractContentStore
private boolean readOnly;
/**
* @param rootDirectoryStr the root under which files will be stored.
* The directory will be created if it does not exist.
*
* Private: for Spring-constructed instances only.
*
* @param rootDirectoryStr
* the root under which files will be stored. The directory will be created if it does not exist.
* @see FileContentStore#FileContentStore(File)
*/
public FileContentStore(String rootDirectoryStr)
private FileContentStore(String rootDirectoryStr)
{
this(new File(rootDirectoryStr));
}
/**
* @param rootDirectory the root under which files will be stored.
* The directory will be created if it does not exist.
* Private: for Spring-constructed instances only.
*
* @param rootDirectory
* the root under which files will be stored. The directory will be created if it does not exist.
*/
public FileContentStore(File rootDirectory)
private FileContentStore(File rootDirectory)
{
if (!rootDirectory.exists())
{
@@ -98,6 +105,36 @@ public class FileContentStore extends AbstractContentStore
readOnly = false;
}
/**
* Public constructor for programmatic use.
*
* @param context
* application context through which events can be published
* @param rootDirectoryStr
* the root under which files will be stored. The directory will be created if it does not exist.
* @see FileContentStore#FileContentStore(File)
*/
public FileContentStore(ConfigurableApplicationContext context, String rootDirectoryStr)
{
this(rootDirectoryStr);
publishEvent(context);
}
/**
* Public constructor for programmatic use.
*
* @param context
* application context through which events can be published
* @param rootDirectory
* the root under which files will be stored. The directory will be created if it does not exist.
*/
public FileContentStore(ConfigurableApplicationContext context, File rootDirectory)
{
this(rootDirectory);
publishEvent(context);
}
public String toString()
{
StringBuilder sb = new StringBuilder(36);
@@ -159,9 +196,9 @@ public class FileContentStore extends AbstractContentStore
* @param newContentUrl the specific URL to use, which may not be in use
* @return Returns a new and unique file
* @throws IOException
* if the file or parent directories couldn't be created or if the URL is already in use.
* if the file or parent directories couldn't be created or if the URL is already in use.
* @throws UnsupportedOperationException
* if the store is read-only
* if the store is read-only
*
* @see #setReadOnly(boolean)
*/
@@ -298,7 +335,7 @@ public class FileContentStore extends AbstractContentStore
}
/**
* @return Returns <tt>true</tt> always
* @return Returns <tt>true</tt> always
*/
public boolean isWriteSupported()
{
@@ -358,6 +395,12 @@ public class FileContentStore extends AbstractContentStore
}
/**
* Returns a writer onto a location based on the date.
*
* @param existingContentReader
* the existing content reader
* @param newContentUrl
* the new content url
* @return Returns a writer onto a location based on the date
*/
public ContentWriter getWriterInternal(ContentReader existingContentReader, String newContentUrl)
@@ -396,6 +439,17 @@ public class FileContentStore extends AbstractContentStore
}
}
/**
* Gets the urls.
*
* @param createdAfter
* the created after date
* @param createdBefore
* the created before dat6e
* @param handler
* the handler
* @return the urls
*/
public void getUrls(Date createdAfter, Date createdBefore, ContentUrlHandler handler)
{
// recursively get all files within the root
@@ -409,11 +463,12 @@ public class FileContentStore extends AbstractContentStore
}
/**
* Returns a list of all files within the given directory and all subdirectories.
* @param directory the current directory to get the files from
* @param handler the callback to use for each URL
* @param createdAfter only get URLs for content create after this date
* @param createdBefore only get URLs for content created before this date
* @return Returns a list of all files within the given directory and all subdirectories
* @return a list of all files within the given directory and all subdirectories
*/
private void getUrls(File directory, ContentUrlHandler handler, Date createdAfter, Date createdBefore)
{
@@ -516,4 +571,41 @@ public class FileContentStore extends AbstractContentStore
// done
return newContentUrl;
}
/**
* Publishes an event to the application context that will notify any interested parties of the existence of this
* content store.
*
* @param context
* the application context
*/
private void publishEvent(ConfigurableApplicationContext context)
{
// If the context isn't running yet, we have to wait until the refresh event
try
{
// Neither context.isActive() or context.isRunning() seem to detect whether the refresh() has completed
context.publishEvent(new FileContentStoreCreatedEvent(this, rootDirectory));
}
catch (IllegalStateException e)
{
context.addApplicationListener(this);
}
}
/*
* (non-Javadoc)
* @see
* org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(ApplicationEvent event)
{
// Once the context has been refreshed, we tell other interested beans about the existence of this content store
// (e.g. for monitoring purposes)
if (event instanceof ContextRefreshedEvent)
{
((ContextRefreshedEvent) event).getApplicationContext().publishEvent(
new FileContentStoreCreatedEvent(this, rootDirectory));
}
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2005-2008 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 received 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.content.filestore;
import java.io.File;
import org.springframework.context.ApplicationEvent;
/**
* A class of event that notifies the listener of the existence of a {@link FileContentStore}. Useful for Monitoring
* purposes.
*
* @author dward
*/
public class FileContentStoreCreatedEvent extends ApplicationEvent
{
private static final long serialVersionUID = 7090069096441126707L;
/** The root directory of the store. */
private final File rootDirectory;
/**
* The Constructor.
*
* @param source
* the source content store
* @param rootDirectory
* the root directory
*/
public FileContentStoreCreatedEvent(FileContentStore source, File rootDirectory)
{
super(source);
this.rootDirectory = rootDirectory;
}
/**
* Gets the root directory.
*
* @return the root directory
*/
public File getRootDirectory()
{
return this.rootDirectory;
}
}

View File

@@ -52,7 +52,7 @@ public class FileContentStoreTest extends AbstractWritableContentStoreTest
// create a store that uses a subdirectory of the temp directory
File tempDir = TempFileProvider.getTempDir();
store = new FileContentStore(
store = new FileContentStore(ctx,
tempDir.getAbsolutePath() +
File.separatorChar +
getName());

View File

@@ -49,7 +49,7 @@ public class NoRandomAccessFileContentStoreTest extends AbstractWritableContentS
// create a store that uses a subdirectory of the temp directory
File tempDir = TempFileProvider.getTempDir();
store = new FileContentStore(
store = new FileContentStore(ctx,
tempDir.getAbsolutePath() +
File.separatorChar +
getName());

View File

@@ -50,7 +50,7 @@ public class ReadOnlyFileContentStoreTest extends AbstractReadOnlyContentStoreTe
// create a store that uses a subdirectory of the temp directory
File tempDir = TempFileProvider.getTempDir();
store = new FileContentStore(
store = new FileContentStore(ctx,
tempDir.getAbsolutePath() +
File.separatorChar +
getName());

View File

@@ -30,7 +30,6 @@ import java.util.Set;
import junit.framework.TestCase;
import org.alfresco.repo.content.AbstractContentStore;
import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.ContentStore.ContentUrlHandler;
@@ -38,6 +37,8 @@ import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.util.GUID;
import org.alfresco.util.TempFileProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
/**
* Tests the content store replicator.
@@ -60,13 +61,17 @@ public class ContentStoreReplicatorTest extends TestCase
{
super.setUp();
// Create a dummy context for message broadcasting
StaticApplicationContext ctx = new StaticApplicationContext();
ctx.refresh();
File tempDir = TempFileProvider.getTempDir();
// create the source file store
String storeDir = tempDir.getAbsolutePath() + File.separatorChar + getName() + File.separatorChar + GUID.generate();
sourceStore = new FileContentStore(storeDir);
sourceStore = new FileContentStore(ctx, storeDir);
// create the target file store
storeDir = tempDir.getAbsolutePath() + File.separatorChar + getName() + File.separatorChar + GUID.generate();
targetStore = new FileContentStore(storeDir);
targetStore = new FileContentStore(ctx, storeDir);
// create the replicator
replicator = new ContentStoreReplicator();

View File

@@ -70,13 +70,13 @@ public class ReplicatingContentStoreTest extends AbstractWritableContentStoreTes
File tempDir = TempFileProvider.getTempDir();
// create a primary file store
String storeDir = tempDir.getAbsolutePath() + File.separatorChar + GUID.generate();
primaryStore = new FileContentStore(storeDir);
primaryStore = new FileContentStore(ctx, storeDir);
// create some secondary file stores
secondaryStores = new ArrayList<ContentStore>(3);
for (int i = 0; i < 4; i++)
{
storeDir = tempDir.getAbsolutePath() + File.separatorChar + GUID.generate();
FileContentStore store = new FileContentStore(storeDir);
FileContentStore store = new FileContentStore(ctx, storeDir);
secondaryStores.add(store);
// Only the first 3 are writable
if (i >= 3)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
* Copyright (C) 2005-2008 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
@@ -18,7 +18,7 @@
* 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
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
@@ -32,6 +32,7 @@ import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.TransformationOptions;
import org.alfresco.util.exec.RuntimeExec;
import org.alfresco.util.exec.RuntimeExec.ExecutionResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -53,6 +54,12 @@ public class ImageMagickContentTransformer extends AbstractImageMagickContentTra
/** the system command executer */
private RuntimeExec executer;
/** the check command executer */
private RuntimeExec checkCommand;
/** the output from the check command */
private String versionString;
/**
* Default constructor
@@ -79,6 +86,29 @@ public class ImageMagickContentTransformer extends AbstractImageMagickContentTra
{
this.executer = executer;
}
/**
* Sets the command that must be executed in order to retrieve version information from the converting executable
* and thus test that the executable itself is present.
*
* @param checkCommand
* command executer to retrieve version information
*/
public void setCheckCommand(RuntimeExec checkCommand)
{
this.checkCommand = checkCommand;
}
/**
* Gets the version string captured from the check command.
*
* @return the version string
*/
public String getVersionString()
{
return this.versionString;
}
/**
* Checks for the JMagick and ImageMagick dependencies, using the common
@@ -92,6 +122,30 @@ public class ImageMagickContentTransformer extends AbstractImageMagickContentTra
throw new AlfrescoRuntimeException("System runtime executer not set");
}
super.init();
if (isAvailable())
{
try
{
ExecutionResult result = this.checkCommand.execute();
if (result.getSuccess())
{
this.versionString = result.getStdOut().trim();
}
else
{
setAvailable(false);
}
}
catch (Throwable e)
{
setAvailable(false);
logger.error(getClass().getSimpleName() + " not available: "
+ (e.getMessage() != null ? e.getMessage() : ""));
// debug so that we can trace the issue if required
logger.debug(e);
}
}
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
* Copyright (C) 2005-2008 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
@@ -18,7 +18,7 @@
* 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
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
@@ -54,6 +54,9 @@ public class PDFToSWFContentTransformer extends AbstractContentTransformer2
/** Used to indicate whether the transformaer in available or not */
private boolean available = false;
/** Stores the output from the check command */
private String versionString;
/** Check and transform command */
private RuntimeExec checkCommand;
private RuntimeExec transformCommand;
@@ -130,15 +133,13 @@ public class PDFToSWFContentTransformer extends AbstractContentTransformer2
{
ExecutionResult result = getCheckCommand().execute();
// check the return code
this.available = result.getSuccess();
if (this.available == false)
if (this.available = result.getSuccess())
{
logger.error("Failed to start SWF2PDF transformer: \n" + result);
this.versionString = result.getStdOut().trim();
}
else
{
// no check - just assume it is available
this.available = true;
logger.error("Failed to start SWF2PDF transformer: \n" + result);
}
// call the base class to make sure that it gets registered
@@ -249,4 +250,24 @@ public class PDFToSWFContentTransformer extends AbstractContentTransformer2
return result;
}
/**
* Signals whether this transformer is available.
*
* @return true, if is available
*/
public boolean isAvailable()
{
return this.available;
}
/**
* Gets the version string captured from the check command.
*
* @return the version string
*/
public String getVersionString()
{
return this.versionString;
}
}