package org.argeo.jcr.proxy; import java.io.IOException; import java.io.InputStream; import java.net.URL; import javax.jcr.Binary; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.nodetype.NodeType; import org.argeo.api.cms.CmsLog; import org.argeo.jcr.JcrException; import org.argeo.jcr.JcrUtils; /** Base class for URL based proxys. */ public abstract class AbstractUrlProxy implements ResourceProxy { private final static CmsLog log = CmsLog.getLog(AbstractUrlProxy.class); private Repository jcrRepository; private Session jcrAdminSession; private String proxyWorkspace = "proxy"; protected abstract Node retrieve(Session session, String path); void init() { try { jcrAdminSession = JcrUtils.loginOrCreateWorkspace(jcrRepository, proxyWorkspace); beforeInitSessionSave(jcrAdminSession); if (jcrAdminSession.hasPendingChanges()) jcrAdminSession.save(); } catch (RepositoryException e) { JcrUtils.discardQuietly(jcrAdminSession); throw new JcrException("Cannot initialize URL proxy", e); } } /** * Called before the (admin) session is saved at the end of the initialization. * Does nothing by default, to be overridden. */ protected void beforeInitSessionSave(Session session) throws RepositoryException { } void destroy() { JcrUtils.logoutQuietly(jcrAdminSession); } /** * Called before the (admin) session is logged out when resources are released. * Does nothing by default, to be overridden. */ protected void beforeDestroySessionLogout() throws RepositoryException { } public Node proxy(String path) { // we open a JCR session with client credentials in order not to use the // admin session in multiple thread or make it a bottleneck. Node nodeAdmin = null; Node nodeClient = null; Session clientSession = null; try { clientSession = jcrRepository.login(proxyWorkspace); if (!clientSession.itemExists(path) || shouldUpdate(clientSession, path)) { nodeAdmin = retrieveAndSave(path); if (nodeAdmin != null) nodeClient = clientSession.getNode(path); } else nodeClient = clientSession.getNode(path); return nodeClient; } catch (RepositoryException e) { throw new JcrException("Cannot proxy " + path, e); } finally { if (nodeClient == null) JcrUtils.logoutQuietly(clientSession); } } protected synchronized Node retrieveAndSave(String path) { try { Node node = retrieve(jcrAdminSession, path); if (node == null) return null; jcrAdminSession.save(); return node; } catch (RepositoryException e) { JcrUtils.discardQuietly(jcrAdminSession); throw new JcrException("Cannot retrieve and save " + path, e); } finally { notifyAll(); } } /** Session is not saved */ protected synchronized Node proxyUrl(Session session, String remoteUrl, String path) throws RepositoryException { Node node = null; if (session.itemExists(path)) { // throw new ArgeoJcrException("Node " + path + " already exists"); } try (InputStream in = new URL(remoteUrl).openStream()) { // URL u = new URL(remoteUrl); // in = u.openStream(); node = importFile(session, path, in); } catch (IOException e) { if (log.isDebugEnabled()) { log.debug("Cannot read " + remoteUrl + ", skipping... " + e.getMessage()); // log.trace("Cannot read because of ", e); } JcrUtils.discardQuietly(session); // } finally { // IOUtils.closeQuietly(in); } return node; } protected synchronized Node importFile(Session session, String path, InputStream in) throws RepositoryException { Binary binary = null; try { Node content = null; Node node = null; if (!session.itemExists(path)) { node = JcrUtils.mkdirs(session, path, NodeType.NT_FILE, NodeType.NT_FOLDER, false); content = node.addNode(Node.JCR_CONTENT, NodeType.NT_UNSTRUCTURED); } else { node = session.getNode(path); content = node.getNode(Node.JCR_CONTENT); } binary = session.getValueFactory().createBinary(in); content.setProperty(Property.JCR_DATA, binary); JcrUtils.updateLastModifiedAndParents(node, null, true); return node; } finally { JcrUtils.closeQuietly(binary); } } /** Whether the file should be updated. */ protected Boolean shouldUpdate(Session clientSession, String nodePath) { return false; } public void setJcrRepository(Repository jcrRepository) { this.jcrRepository = jcrRepository; } public void setProxyWorkspace(String localWorkspace) { this.proxyWorkspace = localWorkspace; } }