diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index aaa359f097..bef5ea0518 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -213,6 +213,29 @@ + + + + OOoJodconverter + + + jodConfig + + + + org.alfresco.util.JodConfig + + + + + + false + + + + + diff --git a/config/alfresco/subsystems/OOoDirect/default/openoffice-transform-context.xml b/config/alfresco/subsystems/OOoDirect/default/openoffice-transform-context.xml index 98ddc74ba2..ae0b92f2fd 100644 --- a/config/alfresco/subsystems/OOoDirect/default/openoffice-transform-context.xml +++ b/config/alfresco/subsystems/OOoDirect/default/openoffice-transform-context.xml @@ -11,9 +11,40 @@ false - + + + + + + + startOpenOffice + + + + + + + + + + + startListener + + + + + ${ooo.enabled} + + ${ooo.host} + + + ${ooo.port} + + + + @@ -48,6 +79,9 @@ + + + @@ -82,6 +116,9 @@ ${openOffice.test.cronExpression} + + + diff --git a/pom.xml b/pom.xml index e0ce29253b..f3ad7349d7 100644 --- a/pom.xml +++ b/pom.xml @@ -53,12 +53,12 @@ org.apache.commons commons-compress - 1.4 + 1.4.1 commons-codec commons-codec - 1.4 + 1.5 commons-io diff --git a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerWorker.java b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerWorker.java index 73eb420a76..fd5343c245 100644 --- a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerWorker.java +++ b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerWorker.java @@ -40,6 +40,7 @@ import org.alfresco.service.cmr.repository.TransformationOptions; import org.alfresco.util.PropertyCheck; import org.alfresco.util.SocketOpenOfficeConnection; import org.alfresco.util.TempFileProvider; +import org.alfresco.util.bean.BooleanBean; import org.apache.pdfbox.exceptions.COSVisitorException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -95,7 +96,7 @@ public class OpenOfficeContentTransformerWorker extends OOoContentTransformerHel { this.documentFormatsConfiguration = path; } - + public boolean isAvailable() { return connection.isConnected(); diff --git a/source/java/org/alfresco/repo/management/subsystems/SubsystemProxyFactory.java b/source/java/org/alfresco/repo/management/subsystems/SubsystemProxyFactory.java index aca08eae41..2af9ea058c 100644 --- a/source/java/org/alfresco/repo/management/subsystems/SubsystemProxyFactory.java +++ b/source/java/org/alfresco/repo/management/subsystems/SubsystemProxyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -28,19 +28,25 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.framework.ProxyFactoryBean; import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; /** * A factory bean, normally used in conjunction with {@link ChildApplicationContextFactory} allowing selected * interfaces in a child application context to be proxied by a bean in the parent application context. This allows * 'hot-swapping' and reconfiguration of entire subsystems. */ -public class SubsystemProxyFactory extends ProxyFactoryBean +public class SubsystemProxyFactory extends ProxyFactoryBean implements ApplicationContextAware { private static final long serialVersionUID = -4186421942840611218L; /** The source application context factory. */ private ApplicationContextFactory sourceApplicationContextFactory; + private String sourceApplicationContextFactoryName; + + private ApplicationContext applicationContext; /** An optional bean name to look up in the source application context **/ private String sourceBeanName; @@ -48,6 +54,7 @@ public class SubsystemProxyFactory extends ProxyFactoryBean private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private ApplicationContext context; private Object sourceBean; + private Object defaultBean; private Map , Object> typedBeans = new HashMap, Object>(7); /** @@ -84,7 +91,18 @@ public class SubsystemProxyFactory extends ProxyFactoryBean /** - * Sets the source application context factory. + * Sets the source application context factory by name. + * + * @param sourceApplicationContextFactoryName + * the name of the sourceApplicationContextFactory to set + */ + public void setSourceApplicationContextFactoryName(String sourceApplicationContextFactoryName) + { + this.sourceApplicationContextFactoryName = sourceApplicationContextFactoryName; + } + + /** + * Sets the source application context factory by reference * * @param sourceApplicationContextFactory * the sourceApplicationContextFactory to set @@ -93,9 +111,33 @@ public class SubsystemProxyFactory extends ProxyFactoryBean { this.sourceApplicationContextFactory = sourceApplicationContextFactory; } + + private ApplicationContextFactory getSourceApplicationContextFactory() + { + if (sourceApplicationContextFactory != null) + { + return sourceApplicationContextFactory; + } + else + { + try + { + return applicationContext.getBean(sourceApplicationContextFactoryName, ApplicationContextFactory.class); + } catch (NoSuchBeanDefinitionException e) + { + return null; + } + } + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + } /** - * Sets optional bean name to target all calls to in the source application context. If not set, an appropriate + * Sets an optional bean name to target all calls to in the source application context. If not set, an appropriate * bean is looked up based on method class. * * @param sourceBeanName @@ -106,6 +148,18 @@ public class SubsystemProxyFactory extends ProxyFactoryBean this.sourceBeanName = sourceBeanName; } + /** + * Sets an optional default bean to be used if the target bean is not found. Generally used when a subsystem does not + * exist. + * + * @param sourceBeanName + * the sourceBeanName to set + */ + public void setDefaultBean(Object defaultBean) + { + this.defaultBean = defaultBean; + } + // Bring our cached copies of the source beans in line with the application context factory, using a RW lock to // ensure consistency private Object locateBean(MethodInvocation mi) @@ -114,52 +168,67 @@ public class SubsystemProxyFactory extends ProxyFactoryBean this.lock.readLock().lock(); try { - ApplicationContext newContext = this.sourceApplicationContextFactory.getApplicationContext(); - if (this.context != newContext) + ApplicationContextFactory sourceApplicationContextFactory = getSourceApplicationContextFactory(); + if (sourceApplicationContextFactory != null) { - // Upgrade the lock - this.lock.readLock().unlock(); - this.lock.writeLock().lock(); - haveWriteLock = true; + ApplicationContext newContext = sourceApplicationContextFactory.getApplicationContext(); + if (this.context != newContext) + { + // Upgrade the lock + this.lock.readLock().unlock(); + this.lock.writeLock().lock(); + haveWriteLock = true; - newContext = this.sourceApplicationContextFactory.getApplicationContext(); - this.context = newContext; - this.typedBeans.clear(); - this.sourceBean = null; - if (this.sourceBeanName != null) - { - this.sourceBean = newContext.getBean(this.sourceBeanName); - } - } - if (this.sourceBean == null) - { - Method method = mi.getMethod(); - Class type = method.getDeclaringClass(); - Object bean = this.typedBeans.get(type); - if (bean == null) - { - // Upgrade the lock if necessary - if (!haveWriteLock) + newContext = sourceApplicationContextFactory.getApplicationContext(); + this.context = newContext; + this.typedBeans.clear(); + this.sourceBean = null; + if (this.sourceBeanName != null) { - this.lock.readLock().unlock(); - this.lock.writeLock().lock(); - haveWriteLock = true; + this.sourceBean = newContext.getBean(this.sourceBeanName); } - bean = this.typedBeans.get(type); + } + if (this.sourceBean == null) + { + Method method = mi.getMethod(); + Class type = method.getDeclaringClass(); + Object bean = this.typedBeans.get(type); if (bean == null) { - Map beans = this.context.getBeansOfType(type); - if (beans.size() != 1) + // Upgrade the lock if necessary + if (!haveWriteLock) { - throw new RuntimeException("Don't know where to route call to method " + method); + this.lock.readLock().unlock(); + this.lock.writeLock().lock(); + haveWriteLock = true; + } + bean = this.typedBeans.get(type); + if (bean == null) + { + Map beans = this.context.getBeansOfType(type); + if (beans.size() == 0 && defaultBean != null) + { + bean = defaultBean; + } + else + { + if (beans.size() != 1) + { + throw new RuntimeException("Don't know where to route call to method " + method); + } + bean = beans.values().iterator().next(); + this.typedBeans.put(type, bean); + } } - bean = beans.values().iterator().next(); - this.typedBeans.put(type, bean); } + return bean; } - return bean; + return this.sourceBean; + } + else + { + return defaultBean; } - return this.sourceBean; } finally { @@ -173,5 +242,4 @@ public class SubsystemProxyFactory extends ProxyFactoryBean } } } - } diff --git a/source/java/org/alfresco/util/JodConfig.java b/source/java/org/alfresco/util/JodConfig.java new file mode 100644 index 0000000000..295f5e306f --- /dev/null +++ b/source/java/org/alfresco/util/JodConfig.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + */ +package org.alfresco.util; + +import java.util.Collection; + +/** + * Supplies OOoJodconverter subsystems config parameters that might clash with the OOoDirect subsystem. + * + * @author Alan Davis + */ +public interface JodConfig +{ + public abstract Collection getPortsCollection(); + + public abstract String getPorts(); + + public abstract void setPorts(String ports); + + public abstract boolean isEnabled(); + + public abstract void setEnabled(boolean enabled); +} \ No newline at end of file diff --git a/source/java/org/alfresco/util/JodConfigImpl.java b/source/java/org/alfresco/util/JodConfigImpl.java new file mode 100644 index 0000000000..88357f5fe4 --- /dev/null +++ b/source/java/org/alfresco/util/JodConfigImpl.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + */ +package org.alfresco.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +/** + * Implementation that supplies OOoJodconverter subsystems config parameters that might clash with the OOoDirect subsystem. + * + * @author Alan Davis + */ +public class JodConfigImpl implements JodConfig +{ + private String ports; + private boolean enabled; + + @Override + public Collection getPortsCollection() + { + return Arrays.asList(ports.trim().split("[, ][, ]*")); + } + + @Override + public String getPorts() + { + return getPortsCollection().toString().replaceAll("[ \\[\\]]", ""); + } + + @Override + public void setPorts(String ports) + { + this.ports = ports; + } + + @Override + public boolean isEnabled() + { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } +} diff --git a/source/java/org/alfresco/util/JodCoordination.java b/source/java/org/alfresco/util/JodCoordination.java new file mode 100644 index 0000000000..1e9c277f21 --- /dev/null +++ b/source/java/org/alfresco/util/JodCoordination.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + */ +package org.alfresco.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Class coordinates with the OOoJodconverter subsystem so that the OOoDirect subsystem does not + * start up its own soffice process it that would clash with the JOD one. It also does not make a + * connection to a JOD started soffice process. + * + * @author Alan Davis + */ +public class JodCoordination +{ + private static Log logger = LogFactory.getLog(JodCoordination.class); + + private Boolean start; + + private boolean oooEnabled; + private boolean oooLocalhost; + private String oooPort; + private JodConfig jodConfig; + + public void setOooEnabled(boolean oooEnabled) + { + this.oooEnabled = oooEnabled; + } + + public void setOooHost(String oooHost) + { + oooLocalhost = oooHost == null || oooHost.equals(SocketOpenOfficeConnection.DEFAULT_HOST); + } + + public void setOooPort(String oooPort) + { + this.oooPort = oooPort; + } + + public void setJodConfig(JodConfig jodConfig) + { + this.jodConfig = jodConfig; + } + + /** + * Returns {@code true} if the direct OOo should be started. This should not take + * place if both direct ooo and jod are enabled and using the same port. + */ + public boolean startOpenOffice() + { + if (start == null) + { + if (logger.isDebugEnabled()) + { + logger.debug("OOoJodconverter subsystem will "+ + (jodConfig.isEnabled() ? "" : "NOT ") + "start an OpenOffice process"); + } + + start = oooEnabled && oooLocalhost; + if (start) + { + if (jodConfig.isEnabled() && jodConfig.getPortsCollection().contains(oooPort)) + { + start = false; + logger.error("Both OOoDirect and OOoJodconverter subsystems are enabled and have specified " + + "the same port number on the localhost."); + logger.error(" ooo.enabled=true"); + logger.error(" ooo.host=localhost"); + logger.error(" ooo.port=" + oooPort); + logger.error(" jodconverter.portNumbers=" + jodConfig.getPorts()); + logger.error(" jodconverter.enabled=true"); + logger.error("The OOoDirect subsystem will not start its OpenOffice process as a result."); + } + else + { + logger.debug("OOoDirect subsystem will start an OpenOffice process"); + } + } + else + { + logger.debug("OOoDirect subsystem will NOT start an OpenOffice process"); + } + } + return start; + } + + /** + * Returns {@code true} if the direct OOo connection listener should be started. This + * should only take place if a remote host is being used or the direct OOo will be started + * on the local host. + */ + public boolean startListener() + { + return (oooEnabled && !oooLocalhost) || startOpenOffice(); + } +} diff --git a/source/java/org/alfresco/util/JodCoordinationBoolean.java b/source/java/org/alfresco/util/JodCoordinationBoolean.java new file mode 100644 index 0000000000..10004e3b6e --- /dev/null +++ b/source/java/org/alfresco/util/JodCoordinationBoolean.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005-2012 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + */ +package org.alfresco.util; + +import org.alfresco.util.bean.BooleanBean; + +/** + * Wraps a {@link #JodCoordination} object to return one of its boolean methods, + * so that it may be used as the input to another bean. + * + * @author Alan Davis + */ +public class JodCoordinationBoolean implements BooleanBean +{ + private JodCoordination jodCoordination; + private String returnValue; + + public void setJodCoordination(JodCoordination jodCoordination) + { + this.jodCoordination = jodCoordination; + } + + public void setReturnValue(String returnValue) + { + this.returnValue = returnValue; + } + + @Override + public boolean isTrue() + { + if ("startOpenOffice".equals(returnValue)) + { + return jodCoordination.startOpenOffice(); + } + else if ("startListener".equals(returnValue)) + { + return jodCoordination.startListener(); + } + else + { + throw new IllegalArgumentException("Expected \"startOpenOffice\" or \"startListener\" " + + "as the returnValue property, but it was \""+returnValue+"\""); + } + } +} diff --git a/source/java/org/alfresco/util/OpenOfficeConnectionTester.java b/source/java/org/alfresco/util/OpenOfficeConnectionTester.java index ca5e86e786..17929852ff 100644 --- a/source/java/org/alfresco/util/OpenOfficeConnectionTester.java +++ b/source/java/org/alfresco/util/OpenOfficeConnectionTester.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2012 Alfresco Software Limited. * * This file is part of Alfresco * @@ -93,8 +93,11 @@ public class OpenOfficeConnectionTester extends AbstractLifecycleBean @Override protected void onBootstrap(ApplicationEvent event) { - checkConnection(); - ((ApplicationContext) event.getSource()).publishEvent(new OpenOfficeConnectionEvent(this.openOfficeMetadata)); + if (connection instanceof SocketOpenOfficeConnection && ((SocketOpenOfficeConnection)connection).isEnabled()) + { + checkConnection(); + ((ApplicationContext) event.getSource()).publishEvent(new OpenOfficeConnectionEvent(this.openOfficeMetadata)); + } } /** diff --git a/source/java/org/alfresco/util/SocketOpenOfficeConnection.java b/source/java/org/alfresco/util/SocketOpenOfficeConnection.java index ec7281cd1c..d7e4c5d282 100644 --- a/source/java/org/alfresco/util/SocketOpenOfficeConnection.java +++ b/source/java/org/alfresco/util/SocketOpenOfficeConnection.java @@ -18,6 +18,8 @@ */ package org.alfresco.util; +import org.alfresco.util.bean.BooleanBean; + import net.sf.jooreports.openoffice.converter.AbstractOpenOfficeDocumentConverter; import net.sf.jooreports.openoffice.converter.OpenOfficeDocumentConverter; import net.sf.jooreports.openoffice.converter.StreamOpenOfficeDocumentConverter; @@ -25,6 +27,7 @@ import net.sf.jooreports.openoffice.converter.StreamOpenOfficeDocumentConverter; public class SocketOpenOfficeConnection extends net.sf.jooreports.openoffice.connection.SocketOpenOfficeConnection { private boolean defaultHost = true; + private boolean enabled = true; public SocketOpenOfficeConnection() { super(); @@ -45,4 +48,17 @@ public class SocketOpenOfficeConnection extends net.sf.jooreports.openoffice.con ? new OpenOfficeDocumentConverter(this) : new StreamOpenOfficeDocumentConverter(this); } + + public void setEnabledFromBean(BooleanBean enabled) + { + this.enabled = enabled.isTrue(); + } + + public boolean isConnected() { + return enabled && super.isConnected(); + } + + public boolean isEnabled() { + return enabled; + } }