/*
* Copyright (C) 2009 eXo Platform SAS.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.services.jcr.impl.core;
import org.exoplatform.commons.utils.PrivilegedFileHelper;
import org.exoplatform.container.configuration.ConfigurationManagerImpl;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.container.xml.PropertiesParam;
import org.exoplatform.container.xml.ValueParam;
import org.exoplatform.services.jcr.JcrImplBaseTest;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.config.CacheEntry;
import org.exoplatform.services.jcr.config.QueryHandlerEntry;
import org.exoplatform.services.jcr.config.RepositoryEntry;
import org.exoplatform.services.jcr.config.RepositoryServiceConfiguration;
import org.exoplatform.services.jcr.config.SimpleParameterEntry;
import org.exoplatform.services.jcr.config.WorkspaceEntry;
import org.exoplatform.services.jcr.core.CredentialsImpl;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.impl.RepositoryContainer;
import org.exoplatform.services.jcr.impl.config.JDBCConfigurationPersister;
import org.exoplatform.services.jcr.impl.config.RepositoryServiceConfigurationImpl;
import org.exoplatform.services.jcr.impl.config.TesterRepositoryServiceConfigurationImpl;
import org.exoplatform.services.jcr.impl.storage.jdbc.JDBCDataContainerConfig.DatabaseStructureType;
import org.exoplatform.services.jcr.util.TesterConfigurationHelper;
import org.exoplatform.services.naming.InitialContextInitializer;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IMarshallingContext;
import org.jibx.runtime.IUnmarshallingContext;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
/**
* @author <a href="mailto:Sergey.Kabashnyuk@gmail.com">Sergey Kabashnyuk</a>
* @version $Id: TestRepositoryManagement.java 11907 2008-03-13 15:36:21Z ksm $
*/
public class TestRepositoryManagement extends JcrImplBaseTest
{
public static int BINDED_DS_COUNT = 100;
private final TesterConfigurationHelper helper;
public TestRepositoryManagement()
{
super();
this.helper = TesterConfigurationHelper.getInstance();
}
public void testAddNewIsolatedWorkspaceWithIncorrectName() throws Exception
{
ManageableRepository repository = null;
try
{
try
{
repository = helper.createRepository(container, DatabaseStructureType.ISOLATED, null);
WorkspaceEntry testWorkspaceEntry = helper.createWorkspaceEntry(DatabaseStructureType.ISOLATED, null);
testWorkspaceEntry.setName("6877876m8_alkgfheriu");
helper.addWorkspace(repository, testWorkspaceEntry);
}
catch (Exception e)
{
fail("WorkspaceEntry is not created");
}
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
public void testAddNewRepository() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
Session session = null;
try
{
session = repository.login(credentials, repository.getConfiguration().getSystemWorkspaceName());
assertNotNull(session.getRootNode());
}
finally
{
if (session != null)
{
session.logout();
}
}
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
public void testMarshalUnmarshalRepositoryConfiguration() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
final long lockManagerTimeOut =
repository.getConfiguration().getWorkspaceEntries().get(0).getLockManager().getParameterLong("time-out");
// 1st marshal configuration
File tempFile = PrivilegedFileHelper.createTempFile("test-config", "xml");
PrivilegedFileHelper.deleteOnExit(tempFile);
IBindingFactory factory = BindingDirectory.getFactory(RepositoryServiceConfiguration.class);
IMarshallingContext mctx = factory.createMarshallingContext();
FileOutputStream saveStream = new FileOutputStream(tempFile);
ArrayList<RepositoryEntry> repositoryEntries = new ArrayList<RepositoryEntry>();
repositoryEntries.add(repository.getConfiguration());
RepositoryServiceConfiguration newRepositoryServiceConfiguration =
new RepositoryServiceConfiguration(repositoryService.getConfig().getDefaultRepositoryName(),
repositoryEntries);
mctx.marshalDocument(newRepositoryServiceConfiguration, "ISO-8859-1", null, saveStream);
saveStream.close();
// 1st unmarshal
factory = BindingDirectory.getFactory(RepositoryServiceConfiguration.class);
IUnmarshallingContext uctx = factory.createUnmarshallingContext();
RepositoryServiceConfiguration conf =
(RepositoryServiceConfiguration)uctx
.unmarshalDocument(PrivilegedFileHelper.fileInputStream(tempFile), null);
// 1st check
RepositoryEntry unmarshledRepositoryEntry =
conf.getRepositoryConfiguration(repository.getConfiguration().getName());
assertEquals(lockManagerTimeOut, unmarshledRepositoryEntry.getWorkspaceEntries().get(0).getLockManager()
.getParameterLong("time-out").longValue());
// 2nd marshal configuration
tempFile = PrivilegedFileHelper.createTempFile("test-config", "xml");
PrivilegedFileHelper.deleteOnExit(tempFile);
factory = BindingDirectory.getFactory(RepositoryServiceConfiguration.class);
mctx = factory.createMarshallingContext();
saveStream = new FileOutputStream(tempFile);
repositoryEntries = new ArrayList<RepositoryEntry>();
repositoryEntries.add(repository.getConfiguration());
newRepositoryServiceConfiguration =
new RepositoryServiceConfiguration(repositoryService.getConfig().getDefaultRepositoryName(),
repositoryEntries);
mctx.marshalDocument(newRepositoryServiceConfiguration, "ISO-8859-1", null, saveStream);
saveStream.close();
// 2nd unmarshal
factory = BindingDirectory.getFactory(RepositoryServiceConfiguration.class);
uctx = factory.createUnmarshallingContext();
conf =
(RepositoryServiceConfiguration)uctx
.unmarshalDocument(PrivilegedFileHelper.fileInputStream(tempFile), null);
// 2nd check
unmarshledRepositoryEntry = conf.getRepositoryConfiguration(repository.getConfiguration().getName());
assertEquals(lockManagerTimeOut, unmarshledRepositoryEntry.getWorkspaceEntries().get(0).getLockManager()
.getParameterLong("time-out").longValue());
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
public void testBackupFilesRepositoryConfiguration() throws Exception
{
InitParams params = new InitParams();
ValueParam confPath = new ValueParam();
confPath.setDescription("JCR configuration file");
confPath.setName("conf-path");
confPath.setValue("jar:/conf/standalone/test-jcr-config-ijdbc-ispn.xml");
params.addParam(confPath);
ValueParam maxBackupFiles = new ValueParam();
maxBackupFiles.setName("max-backup-files");
maxBackupFiles.setValue("5");
params.addParam(maxBackupFiles);
ConfigurationManagerImpl configManager =
(ConfigurationManagerImpl)container.getComponentInstanceOfType(ConfigurationManagerImpl.class);
InitialContextInitializer context =
(InitialContextInitializer)container.getComponentInstanceOfType(InitialContextInitializer.class);
String defaultRepositoryName = repositoryService.getConfig().getDefaultRepositoryName();
TesterRepositoryServiceConfigurationImpl repositoryServiceConfiguration =
new TesterRepositoryServiceConfigurationImpl(new RepositoryServiceConfigurationImpl(params, configManager,
context));
repositoryServiceConfiguration.setDefaultRepositoryName(defaultRepositoryName);
File configPath = repositoryServiceConfiguration.getContentPath();
final String configFileName = repositoryServiceConfiguration.getConfigFileName();
for (int i = 1; i <= 10; i++)
{
repositoryServiceConfiguration.retain();
}
String[] files = configPath.list(new FilenameFilter()
{
public boolean accept(File dir, String name)
{
return name.startsWith(configFileName) && Character.isDigit(name.charAt(name.length() - 1));
}
});
assertEquals(5, files.length);
}
public void testAddNewRepositoryWithSameName() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
try
{
RepositoryEntry rEntry = helper.createRepositoryEntry(DatabaseStructureType.SINGLE, null, null, true);
rEntry.setName(repository.getConfiguration().getName());
helper.createRepository(container, rEntry);
fail();
}
catch (Exception e)
{
// ok
}
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
public void testCanRemove() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
RepositoryService service = (RepositoryService)container.getComponentInstanceOfType(RepositoryService.class);
SessionImpl session =
(SessionImpl)repository.login(credentials, repository.getConfiguration().getSystemWorkspaceName());
assertFalse(service.canRemoveRepository(repository.getConfiguration().getName()));
session.logout();
assertTrue(service.canRemoveRepository(repository.getConfiguration().getName()));
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
/**
* Checks if {@link RepositoryService#removeRepository(String, boolean)}} with
* parameter <code>forceRemove=true</code> can remove repository with alive sessions.
*/
public void testForceRemove() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
RepositoryService service = (RepositoryService)container.getComponentInstanceOfType(RepositoryService.class);
SessionImpl session =
(SessionImpl)repository.login(credentials, repository.getConfiguration().getSystemWorkspaceName());
assertFalse(service.canRemoveRepository(repository.getConfiguration().getName()));
try
{
service.removeRepository(repository.getConfiguration().getName(), false);
fail();
}
catch (RepositoryException e)
{
//ok
}
try
{
service.removeRepository(repository.getConfiguration().getName(), true);
repository = null;
}
catch (RepositoryException e)
{
fail("Repository should be removed with opened sessions.");
}
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
public void testInitNameSpaces() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
SessionImpl session = null;
try
{
session =
(SessionImpl)repository.login(credentials, repository.getConfiguration().getSystemWorkspaceName());
assertEquals("http://www.apache.org/jackrabbit/test", session.getNamespaceURI("test"));
assertEquals("http://www.exoplatform.org/jcr/test/1.0", session.getNamespaceURI("exojcrtest"));
}
finally
{
if (session != null)
{
session.logout();
}
}
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
public void testInitNodeTypes() throws Exception
{
ManageableRepository repository = null;
try
{
repository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
SessionImpl session = null;
try
{
session =
(SessionImpl)repository.login(credentials, repository.getConfiguration().getSystemWorkspaceName());
// check if nt:folder nodetype exists
session.getRootNode().addNode("folder", "nt:folder");
session.save();
}
finally
{
if (session != null)
{
session.logout();
}
}
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
public void testRemove() throws Exception
{
ManageableRepository repository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
RepositoryService service = (RepositoryService)container.getComponentInstanceOfType(RepositoryService.class);
service.removeRepository(repository.getConfiguration().getName());
try
{
service.getRepository(repository.getConfiguration().getName());
}
catch (Exception e)
{
}
}
public void testAddNewRepositorMultiThreading() throws Exception
{
int theadsCount = 10;
RepositoryCreationThread[] threads = new RepositoryCreationThread[theadsCount];
try
{
CountDownLatch latcher = new CountDownLatch(1);
for (int i = 0; i < theadsCount; i++)
{
threads[i] = new RepositoryCreationThread(latcher);
threads[i].start();
}
latcher.countDown();
for (int i = 0; i < theadsCount; i++)
{
threads[i].join();
}
PropertiesParam props = new PropertiesParam();
props.setProperty("dialect", "auto");
props.setProperty("source-name", "jdbcjcr");
JDBCConfigurationPersister persiter = new JDBCConfigurationPersister();
persiter.init(props);
IBindingFactory bfact = BindingDirectory.getFactory(RepositoryServiceConfiguration.class);
IMarshallingContext mctx = bfact.createMarshallingContext();
OutputStream saveStream = new ByteArrayOutputStream();
mctx.marshalDocument(repositoryService.getConfig(), "ISO-8859-1", null, saveStream);
saveStream.close();
persiter.write(new ByteArrayInputStream(((ByteArrayOutputStream)saveStream).toByteArray()));
IBindingFactory factory = BindingDirectory.getFactory(RepositoryServiceConfiguration.class);
IUnmarshallingContext uctx = factory.createUnmarshallingContext();
RepositoryServiceConfiguration storedConf =
(RepositoryServiceConfiguration)uctx.unmarshalDocument(persiter.read(), null);
for (int i = 0; i < theadsCount; i++)
{
// test if respository has been created
ManageableRepository repository = threads[i].getRepository();
assertNotNull(repository);
// check configuration in persiter
storedConf.getRepositoryConfiguration(repository.getConfiguration().getName());
// check configuration in RepositoryServic
assertNotNull(repositoryService.getConfig().getRepositoryConfiguration(
repository.getConfiguration().getName()));
// login into newly created repository
ManageableRepository newRepository =
repositoryService.getRepository(repository.getConfiguration().getName());
Session session = null;
try
{
session = repository.login(credentials, newRepository.getConfiguration().getSystemWorkspaceName());
assertNotNull(session.getRootNode());
}
finally
{
if (session != null)
{
session.logout();
}
}
}
}
finally
{
for (int i = 0; i < theadsCount; i++)
{
helper.removeRepository(container, threads[i].getRepository().getConfiguration().getName());
}
}
}
private class RepositoryCreationThread extends Thread
{
private CountDownLatch latcher;
private ManageableRepository tRrepository;
RepositoryCreationThread(CountDownLatch latcher)
{
this.latcher = latcher;
}
/**
* {@inheritDoc}
*/
public void run()
{
try
{
latcher.await();
tRrepository = helper.createRepository(container, DatabaseStructureType.SINGLE, null);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public ManageableRepository getRepository()
{
return tRrepository;
}
}
public void testCreateAterRemoveCheckOldContent() throws Exception
{
ManageableRepository newRepository = null;
try
{
RepositoryService service = (RepositoryService)container.getComponentInstanceOfType(RepositoryService.class);
RepositoryEntry repoEntry = helper.createRepositoryEntry(DatabaseStructureType.SINGLE, null, null, true);
try
{
Class
.forName("org.exoplatform.services.jcr.impl.dataflow.persistent.infinispan.ISPNCacheWorkspaceStorageCache");
List<SimpleParameterEntry> cacheParams = new ArrayList<SimpleParameterEntry>();
cacheParams.add(new SimpleParameterEntry("infinispan-configuration",
"conf/standalone/test-infinispan-config.xml"));
CacheEntry cacheEntry = new CacheEntry(cacheParams);
cacheEntry
.setType("org.exoplatform.services.jcr.impl.dataflow.persistent.infinispan.ISPNCacheWorkspaceStorageCache");
cacheEntry.setEnabled(true);
List<WorkspaceEntry> wsList = repoEntry.getWorkspaceEntries();
wsList.get(0).setCache(cacheEntry);
repoEntry.setWorkspaceEntries(wsList);
}
catch (ClassNotFoundException e)
{
}
service.createRepository(repoEntry);
service.getConfig().retain();
ManageableRepository repository = service.getRepository(repoEntry.getName());
// add content
Session session =
repository.login(new CredentialsImpl("admin", "admin".toCharArray()), repository.getConfiguration()
.getSystemWorkspaceName());
session.getRootNode().addNode("test");
session.save();
session.logout();
// copy repository configuration
RepositoryEntry repositoryEntry = helper.copyRepositoryEntry(repository.getConfiguration());
String newDatasourceName = helper.createDatasource();
for (WorkspaceEntry ws : repositoryEntry.getWorkspaceEntries())
{
if (ws.getContainer().hasParameter("source-name"))
{
ws.getContainer().addParameter(new SimpleParameterEntry("source-name", newDatasourceName));
}
if (ws.getLockManager().hasParameter("infinispan-cl-cache.jdbc.datasource"))
{
ws.getLockManager().addParameter(new SimpleParameterEntry("infinispan-cl-cache.jdbc.datasource", newDatasourceName));
}
}
service.removeRepository(repository.getConfiguration().getName());
try
{
service.getRepository(repository.getConfiguration().getName());
fail();
}
catch (Exception e)
{
}
// create new repository
service.createRepository(repositoryEntry);
service.getConfig().retain();
newRepository = service.getRepository(repositoryEntry.getName());
Session newSession = null;
try
{
newSession =
newRepository.login(new CredentialsImpl("admin", "admin".toCharArray()), newRepository
.getConfiguration().getSystemWorkspaceName());
try
{
newSession.getRootNode().getNode("test");
fail("Node 'test' should not exists after remove repository and recreate new.");
}
catch (PathNotFoundException e)
{
//ok
}
}
finally
{
if (newSession != null)
{
newSession.logout();
}
}
}
finally
{
if (newRepository != null)
{
helper.removeRepository(container, newRepository.getConfiguration().getName());
}
}
}
public void testRepositoryContainerGCedAfterStop() throws Exception
{
int numberOfRepositories = 3;
int GCTimeoutUntilTenuredCleaned = 2 * 60 * 1000; // 2 minutes
// This object is going to be placed into Tenured generation of garbage collector
// this will be used as indicator that Tenured generation is touched by GC
WeakHashMap<RepositoryContainer, Object> repositoryContainersInMemory =
new WeakHashMap<RepositoryContainer, Object>();
for (int i = 0; i < numberOfRepositories; i++)
{
ManageableRepository repository = null;
try
{
repository = createRepositoryWithQueryHandler();
RepositoryContainer repositoryContainer =
helper.getRepositoryContainer(container, repository.getConfiguration().getName());
repositoryContainersInMemory.put(repositoryContainer, null);
SessionImpl session =
(SessionImpl)repository.login(credentials, repository.getConfiguration().getSystemWorkspaceName());
session.logout();
}
finally
{
if (repository != null)
{
helper.removeRepository(container, repository.getConfiguration().getName());
}
}
}
long purgeStartTime = System.currentTimeMillis();
while (repositoryContainersInMemory.size() > 0
&& (System.currentTimeMillis() - purgeStartTime < GCTimeoutUntilTenuredCleaned))
{
System.gc();
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
}
}
if (repositoryContainersInMemory.size() > 0)
{
fail("Memmory leak spotted. Please check. No RepositoryContainer instances should be in the memory. But "
+ repositoryContainersInMemory.size() + " found.");
}
}
private ManageableRepository createRepositoryWithQueryHandler() throws Exception
{
RepositoryEntry repoEntry = helper.createRepositoryEntry(DatabaseStructureType.SINGLE, null, null, true);
// modify configuration
WorkspaceEntry workspaceEntry = repoEntry.getWorkspaceEntries().get(0);
QueryHandlerEntry queryHandler = workspaceEntry.getQueryHandler();
if (helper.ispnCacheEnabled())
{
// Use Infinispan components for core.ispn project
queryHandler.addParameter(new SimpleParameterEntry("changesfilter-class",
"org.exoplatform.services.jcr.impl.core.query.ispn.ISPNIndexChangesFilter"));
queryHandler.addParameter(new SimpleParameterEntry("infinispan-configuration",
"conf/standalone/cluster/test-infinispan-indexer.xml"));
queryHandler.addParameter(new SimpleParameterEntry("jgroups-configuration",
"jar:/conf/standalone/cluster/udp-mux.xml"));
queryHandler.addParameter(new SimpleParameterEntry("infinispan-cluster-name", "JCR-cluster"));
}
return helper.createRepository(container, repoEntry);
}
}