package play.modules.cream.helpers; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.jcr.Repository; import org.apache.jackrabbit.core.RepositoryImpl; import org.apache.jackrabbit.core.config.RepositoryConfig; import org.apache.jackrabbit.rmi.repository.URLRemoteRepository; import play.Play; import play.exceptions.UnexpectedException; import play.vfs.VirtualFile; /** * Jcr and Jackrabbit utilities for repository creation * * @author igor.vaynberg */ public class JcrRepositoryCreationHelper { /** * Copies a resource to a {@link java.io.File} * * @param source * classpath or virtual file path to resource * @param destination * destination file */ public static void copyResourceToFile(String source, java.io.File destination) { VirtualFile conf = Play.getVirtualFile(source); final InputStream in; if (conf == null || !conf.exists()) { in = JcrRepositoryCreationHelper.class.getResourceAsStream(source); } else { in = conf.inputstream(); } if (in == null) { throw new UnexpectedException("Resource: " + source + " does not exist"); } try { final FileOutputStream fos = new FileOutputStream(destination); copyStream(in, fos, 4096); fos.close(); in.close(); } catch (IOException e) { throw new UnexpectedException("Could not copy class resource: " + source + " to destination: " + destination.getAbsolutePath()); } } /** * Writes the input stream to the output stream. Input is done without a * Reader object, meaning that the input is copied in its raw form. * * @param in * The input stream * @param out * The output stream * @param bufSize * The buffer size. A good value is 4096. * @return Number of bytes copied from one stream to the other * @throws IOException */ public static int copyStream(final InputStream in, final OutputStream out, final int bufSize) throws IOException { if (bufSize <= 0) { throw new IllegalArgumentException("The parameter 'bufSize' must not be <= 0"); } final byte[] buffer = new byte[bufSize]; int bytesCopied = 0; while (true) { int byteCount = in.read(buffer, 0, buffer.length); if (byteCount <= 0) { break; } out.write(buffer, 0, byteCount); bytesCopied += byteCount; } return bytesCopied; } /** * Creates a repository at the location specified by the url. Url must start * with <code>file://</code>. * * @param url * repository home url * @param repoConfiguration * @return repository instance * @throws RuntimeException * if repository could not be created */ public static Repository createFileRepository(String url, String repoConfiguration) { try { // ensure home dir exists final File home = new File(url.substring(6)); mkdirs(home); // create default config file if one is not present File cfg = new File(home, "repository.xml"); if (!cfg.exists()) { copyResourceToFile(repoConfiguration, cfg); } // TODO: try to clean from Jackrabbit dependency InputStream configStream = new FileInputStream(cfg); RepositoryConfig config = RepositoryConfig.create(configStream, home.getAbsolutePath()); return RepositoryImpl.create(config); // // --> EXAMPLE FOR REAL JCR2 INIT, REQUIRES JAVA6, THEREFORE NOT // IMPLEMENTED!!! // // Properties properties = new Properties(); // properties.load(configStream); // // Repository repository = null; // // for (RepositoryFactory factory : // ServiceLoader.load(RepositoryFactory.class)) { // repository = factory.getRepository(properties); // if(repository != null) { // break; // } // } // // return repository; } catch (Exception e) { throw new RuntimeException("Could not create file repository at url: " + url, e); } } /** * Creates a jackrabbit repository based on the url. Accepted urls are * <code>rmi://</code> , <code>file://</code> and <code>http://</code> * * @param url * repository url * @param repoConfiguration * location of the repository.xml in classpath * @return repository instance * @throws RuntimeException * if repository could not be created */ public static Repository createRepository(String url, String repoConfiguration) { if (url.startsWith("rmi://")) { return createRmiRepository(url); } else if (url.startsWith("file://")) { return createFileRepository(url, repoConfiguration); } else if (url.startsWith("http://")) { return createUrlRemoteRepository(url); } else { throw new RuntimeException( "Unsupported repository location url. Only prefix rmi://, file:// or http:// are supported"); } } /** * Creates a repository at the location specified by the url. Url must start * with <code>http://</code>. * * @param url * repository home url * @return repository instance * @throws RuntimeException * if repository could not be created */ public static Repository createUrlRemoteRepository(String url) { try { return new URLRemoteRepository(url); } catch (Exception e) { throw new RuntimeException("Could not create url remote repository instance at url: " + url, e); } } /** * Creates a repository at the location specified by the url. Url must start * with <code>rmi://</code>. * * @param url * repository home url * @return repository instance * @throws RuntimeException * if repository could not be created */ public static Repository createRmiRepository(String url) { try { JcrRepositoryCreationHelper.class.getClassLoader().loadClass( "org.apache.jackrabbit.rmi.client.ClientRepositoryFactory"); return RmiRepositoryFactory.getRmiRepository(url); } catch (Exception e) { throw new RuntimeException("Could not create rmi repository instance at url: " + url, e); } } /** * {@link java.io.File#mkdirs()} that throws runtime exception if it fails * * @param file */ public static void mkdirs(java.io.File file) { if (!file.exists()) { if (!file.mkdirs()) { throw new RuntimeException("Could not create directory: " + file.getAbsolutePath()); } } } /** * Constructor */ private JcrRepositoryCreationHelper() { } }