Author: asoldano
Date: 2015-04-01 16:33:19 -0400 (Wed, 01 Apr 2015)
New Revision: 19610
Added:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/AbstractHTTPConduitFactoryWrapper.java
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/DefaultHTTPConduitFactoryWrapper.java
Modified:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/Constants.java
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/BeanCustomizer.java
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/JBossWSNonSpringBusFactory.java
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/JBossWSSpringBusFactory.java
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/SecurityActions.java
stack/cxf/trunk/modules/testsuite/pom.xml
Log:
[JBWS-3901] Install a HTTPConduitFactory wrapper that sets few default HTTPConduit values
obtained from system properties
Modified:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/Constants.java
===================================================================
---
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/Constants.java 2015-03-30
15:11:57 UTC (rev 19609)
+++
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/Constants.java 2015-04-01
20:33:19 UTC (rev 19610)
@@ -48,6 +48,12 @@
public static final String CXF_WS_DISCOVERY_ENABLED =
"cxf.ws-discovery.enabled";
public static final String JBWS_CXF_DISABLE_HANDLER_AUTH_CHECKS =
"org.jboss.ws.cxf.disableHandlerAuthChecks";
public static final String JBWS_CXF_NO_LOCAL_BC =
"org.jboss.ws.cxf.noLocalBC";
+ public static final String CXF_CLIENT_ALLOW_CHUNKING =
"cxf.client.allowChunking";
+ public static final String CXF_CLIENT_CHUNKING_THRESHOLD =
"cxf.client.chunkingThreshold";
+ public static final String CXF_CLIENT_CONNECTION_TIMEOUT =
"cxf.client.connectionTimeout";
+ public static final String CXF_CLIENT_RECEIVE_TIMEOUT =
"cxf.client.receiveTimeout";
+ public static final String CXF_CLIENT_CONNECTION = "cxf.client.connection";
+ public static final String CXF_TLS_CLIENT_DISABLE_CN_CHECK =
"cxf.tls-client.disableCNCheck";
public static final String JBWS_CXF_JAXWS_CLIENT_BUS_STRATEGY =
"org.jboss.ws.cxf.jaxws-client.bus.strategy";
public static final String THREAD_BUS_STRATEGY = "THREAD_BUS";
Added:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/AbstractHTTPConduitFactoryWrapper.java
===================================================================
---
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/AbstractHTTPConduitFactoryWrapper.java
(rev 0)
+++
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/AbstractHTTPConduitFactoryWrapper.java 2015-04-01
20:33:19 UTC (rev 19610)
@@ -0,0 +1,105 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2015, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.wsf.stack.cxf.client.configuration;
+
+import java.io.IOException;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transport.http.HTTPConduitFactory;
+import org.apache.cxf.transport.http.HTTPTransportFactory;
+import org.apache.cxf.ws.addressing.EndpointReferenceType;
+
+/**
+ * Abstract wrapper over HTTPConduitFactory for configuring HTTPConduit instances with
default
+ * values just after they've been created.
+ * This class can be extended to establish and set default HTTPConduit values in
different ways.
+ *
+ * @author alessio.soldano(a)jboss.com
+ * @since 1-Apr-2015
+ */
+public abstract class AbstractHTTPConduitFactoryWrapper implements HTTPConduitFactory
+{
+ private HTTPConduitFactory delegate;
+
+ /**
+ * Installs the current wrapper in the specified Bus instance.
+ *
+ * @param bus The Bus instance to install the wrapper in
+ */
+ public void install(Bus bus)
+ {
+ delegate = bus.getExtension(HTTPConduitFactory.class);
+ bus.setExtension(this, HTTPConduitFactory.class);
+ }
+
+ @Override
+ public HTTPConduit createConduit(HTTPTransportFactory f, Bus b, EndpointInfo
localInfo, EndpointReferenceType target)
+ throws IOException
+ {
+ HTTPConduit conduit = null;
+ if (delegate != null)
+ {
+ conduit = delegate.createConduit(f, b, localInfo, target);
+ }
+ else
+ {
+ conduit = createNewConduit(f, b, localInfo, target);
+ }
+ if (conduit != null)
+ {
+ configureConduit(conduit);
+ }
+ return conduit;
+ }
+
+ /**
+ * Returns the HTTPConduitFactory instance that this wrapper delegates to
+ *
+ * @return The wrapper's delegate
+ */
+ public HTTPConduitFactory getDelegate()
+ {
+ return delegate;
+ }
+
+ /**
+ * Creates a new HTTPConduit instance; this is used internally when no delegate is
available for getting a HTTPConduit instance to configure
+ *
+ * @param f The current HTTPTransportFactory
+ * @param b The current Bus
+ * @param localInfo The current EndpointInfo
+ * @param target The EndpointReferenceType
+ * @return A new HTTPConduit instance
+ * @throws IOException
+ */
+ protected abstract HTTPConduit createNewConduit(HTTPTransportFactory f, Bus b,
EndpointInfo localInfo,
+ EndpointReferenceType target) throws IOException;
+
+ /**
+ * Configures the specified HTTPConduit instance with default values
+ *
+ * @param conduit The HTTPConduit instance to be configured
+ */
+ protected abstract void configureConduit(HTTPConduit conduit);
+}
Property changes on:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/AbstractHTTPConduitFactoryWrapper.java
___________________________________________________________________
Added: svn:keywords
+ Rev Date
Added: svn:eol-style
+ native
Modified:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/BeanCustomizer.java
===================================================================
---
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/BeanCustomizer.java 2015-03-30
15:11:57 UTC (rev 19609)
+++
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/BeanCustomizer.java 2015-04-01
20:33:19 UTC (rev 19610)
@@ -21,13 +21,11 @@
*/
package org.jboss.wsf.stack.cxf.client.configuration;
-import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.databinding.DataBinding;
import org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory;
import org.apache.cxf.frontend.ClientProxyFactoryBean;
import org.apache.cxf.jaxb.JAXBDataBinding;
import org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean;
-import org.apache.cxf.transport.http.HTTPConduit;
import org.jboss.ws.api.binding.BindingCustomization;
import org.jboss.ws.api.binding.JAXBBindingCustomization;
@@ -50,10 +48,6 @@
{
configureClientProxyFactoryBean((ClientProxyFactoryBean)beanInstance);
}
- else if (beanInstance instanceof HTTPConduit)
- {
- configureHTTPConduit((HTTPConduit)beanInstance);
- }
//add other beans configuration here below
}
@@ -117,27 +111,6 @@
//add other configurations here below
}
- /**
- * Configure the HTTPConduit; currently allows for setting disableCNcheck in TLS
client parameters according
- * to the JBoss' org.jboss.security.ignoreHttpsHost system property.
- *
- * @param conduit
- */
- protected void configureHTTPConduit(HTTPConduit conduit)
- {
- TLSClientParameters parameters = conduit.getTlsClientParameters();
- if (parameters == null) //don't do anything when user already provided a
configuration
- {
- parameters = new TLSClientParameters();
- parameters.setUseHttpsURLConnectionDefaultSslSocketFactory(true);
- if (SecurityActions.getBoolean("org.jboss.security.ignoreHttpsHost"))
- {
- parameters.setDisableCNCheck(true);
- }
- conduit.setTlsClientParameters(parameters);
- }
- }
-
@SuppressWarnings("unchecked")
protected static void configureBindingCustomization(DataBinding db,
BindingCustomization customization)
{
Added:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/DefaultHTTPConduitFactoryWrapper.java
===================================================================
---
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/DefaultHTTPConduitFactoryWrapper.java
(rev 0)
+++
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/DefaultHTTPConduitFactoryWrapper.java 2015-04-01
20:33:19 UTC (rev 19610)
@@ -0,0 +1,160 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2015, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * 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.jboss.wsf.stack.cxf.client.configuration;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.configuration.jsse.TLSClientParameters;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transport.http.HTTPTransportFactory;
+import org.apache.cxf.transport.http.URLConnectionHTTPConduit;
+import org.apache.cxf.transports.http.configuration.ConnectionType;
+import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
+import org.apache.cxf.ws.addressing.EndpointReferenceType;
+import org.jboss.wsf.stack.cxf.client.Constants;
+
+/**
+ * The default wrapper of HTTPConduitFactory, which gets default configuration values
from a
+ * map. The configuration map can also be populated by system properties.
+ *
+ * @author alessio.soldano(a)jboss.com
+ * @since 1-Apr-2015
+ */
+public final class DefaultHTTPConduitFactoryWrapper extends
AbstractHTTPConduitFactoryWrapper
+{
+ private static final Map<String, Object> defaultConfiguration;
+ static {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put(Constants.CXF_CLIENT_ALLOW_CHUNKING,
SecurityActions.getBoolean(Constants.CXF_CLIENT_ALLOW_CHUNKING, null));
+ map.put(Constants.CXF_CLIENT_CHUNKING_THRESHOLD,
SecurityActions.getInteger(Constants.CXF_CLIENT_CHUNKING_THRESHOLD, null));
+ map.put(Constants.CXF_TLS_CLIENT_DISABLE_CN_CHECK,
SecurityActions.getBoolean(Constants.CXF_TLS_CLIENT_DISABLE_CN_CHECK));
+ map.put(Constants.CXF_CLIENT_CONNECTION_TIMEOUT,
SecurityActions.getLong(Constants.CXF_CLIENT_CONNECTION_TIMEOUT, null));
+ map.put(Constants.CXF_CLIENT_RECEIVE_TIMEOUT,
SecurityActions.getLong(Constants.CXF_CLIENT_RECEIVE_TIMEOUT, null));
+ map.put(Constants.CXF_CLIENT_CONNECTION,
SecurityActions.getSystemProperty(Constants.CXF_CLIENT_CONNECTION, null));
+ defaultConfiguration = Collections.unmodifiableMap(map);
+ }
+
+ private final Map<String, Object> configuration;
+
+ public DefaultHTTPConduitFactoryWrapper()
+ {
+ this.configuration = defaultConfiguration;
+ }
+
+ public DefaultHTTPConduitFactoryWrapper(Map<String, Object> configuration,
boolean useSystemDefault)
+ {
+ if (configuration == null) {
+ throw new IllegalArgumentException();
+ }
+ if (useSystemDefault) {
+ this.configuration = new HashMap<String, Object>();
+ for (Entry<String, Object> e : defaultConfiguration.entrySet()) {
+ final String key = e.getKey();
+ this.configuration.put(key, e.getValue());
+ final Object providedValue = configuration.get(key);
+ if (providedValue != null) {
+ this.configuration.put(key, providedValue);
+ }
+ }
+ } else {
+ this.configuration = configuration;
+ }
+ }
+
+ protected HTTPConduit createNewConduit(HTTPTransportFactory f, Bus b, EndpointInfo
localInfo,
+ EndpointReferenceType target) throws IOException
+ {
+ return new URLConnectionHTTPConduit(b, localInfo, target);
+ }
+
+ protected void configureConduit(HTTPConduit conduit)
+ {
+ configureTLSClient(conduit);
+ configureHTTPClientPolicy(conduit);
+ }
+
+ private void configureTLSClient(HTTPConduit conduit)
+ {
+ TLSClientParameters parameters = conduit.getTlsClientParameters();
+ if (parameters == null) //don't do anything when user already provided a
configuration
+ {
+ parameters = new TLSClientParameters();
+ parameters.setUseHttpsURLConnectionDefaultSslSocketFactory(true);
+ if
(Boolean.TRUE.equals((Boolean)configuration.get(Constants.CXF_TLS_CLIENT_DISABLE_CN_CHECK)))
{
+ parameters.setDisableCNCheck(true);
+ }
+ conduit.setTlsClientParameters(parameters);
+ }
+ }
+
+ private void configureHTTPClientPolicy(HTTPConduit conduit)
+ {
+ boolean set = false;
+
+ final Boolean allowChunking =
(Boolean)configuration.get(Constants.CXF_CLIENT_ALLOW_CHUNKING);
+ set = set || (allowChunking != null);
+ final Integer chunkingThreshold =
(Integer)configuration.get(Constants.CXF_CLIENT_CHUNKING_THRESHOLD);
+ set = set || (chunkingThreshold != null);
+ final Long connectionTimeout =
(Long)configuration.get(Constants.CXF_CLIENT_CONNECTION_TIMEOUT);
+ set = set || (connectionTimeout != null);
+ final Long receiveTimeout =
(Long)configuration.get(Constants.CXF_CLIENT_RECEIVE_TIMEOUT);
+ set = set || (receiveTimeout != null);
+ final String connection =
(String)configuration.get(Constants.CXF_CLIENT_CONNECTION);
+ set = set || (connection != null);
+
+ if (set)
+ {
+ HTTPClientPolicy httpClientPolicy = conduit.getClient();
+ if (httpClientPolicy == null)
+ {
+ httpClientPolicy = new HTTPClientPolicy();
+ conduit.setClient(httpClientPolicy);
+ }
+ if (allowChunking != null)
+ {
+ httpClientPolicy.setAllowChunking(allowChunking);
+ }
+ if (chunkingThreshold != null)
+ {
+ httpClientPolicy.setChunkingThreshold(chunkingThreshold);
+ }
+ if (connectionTimeout != null)
+ {
+ httpClientPolicy.setConnectionTimeout(connectionTimeout);
+ }
+ if (receiveTimeout != null)
+ {
+ httpClientPolicy.setReceiveTimeout(receiveTimeout);
+ }
+ if (connection != null)
+ {
+ httpClientPolicy.setConnection(ConnectionType.fromValue(connection));
+ }
+ }
+ }
+}
Property changes on:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/DefaultHTTPConduitFactoryWrapper.java
___________________________________________________________________
Added: svn:keywords
+ Rev Date
Added: svn:eol-style
+ native
Modified:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/JBossWSNonSpringBusFactory.java
===================================================================
---
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/JBossWSNonSpringBusFactory.java 2015-03-30
15:11:57 UTC (rev 19609)
+++
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/JBossWSNonSpringBusFactory.java 2015-04-01
20:33:19 UTC (rev 19610)
@@ -59,6 +59,8 @@
possiblySetDefaultBus(bus);
initializeBus(bus);
bus.initialize();
+
+ new DefaultHTTPConduitFactoryWrapper().install(bus);
return bus;
}
Modified:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/JBossWSSpringBusFactory.java
===================================================================
---
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/JBossWSSpringBusFactory.java 2015-03-30
15:11:57 UTC (rev 19609)
+++
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/JBossWSSpringBusFactory.java 2015-04-01
20:33:19 UTC (rev 19610)
@@ -112,6 +112,8 @@
initializeBus(bus);
registerAppContextLifeCycleListener(bus, bac);
+
+ new DefaultHTTPConduitFactoryWrapper().install(bus);
return bus;
}
Modified:
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/SecurityActions.java
===================================================================
---
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/SecurityActions.java 2015-03-30
15:11:57 UTC (rev 19609)
+++
stack/cxf/trunk/modules/client/src/main/java/org/jboss/wsf/stack/cxf/client/configuration/SecurityActions.java 2015-04-01
20:33:19 UTC (rev 19610)
@@ -81,6 +81,27 @@
}
}
+ static Boolean getBoolean(final String propName, final Boolean defaultValue)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null)
+ {
+ String s = System.getProperty(propName);
+ return (s != null) ? Boolean.valueOf(s) : defaultValue;
+ }
+ else
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<Boolean>()
+ {
+ public Boolean run()
+ {
+ String s = getSystemProperty(propName, null);
+ return (s != null) ? Boolean.valueOf(s) : defaultValue;
+ }
+ });
+ }
+ }
+
static boolean getBoolean(final String propName)
{
SecurityManager sm = System.getSecurityManager();
@@ -100,6 +121,63 @@
}
}
+ static Long getLong(final String propName, final Long defaultValue)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null)
+ {
+ return Long.getLong(propName, defaultValue);
+ }
+ else
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<Long>()
+ {
+ public Long run()
+ {
+ return Long.getLong(propName, defaultValue);
+ }
+ });
+ }
+ }
+
+ static Integer getInteger(final String propName, final Integer defaultValue)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null)
+ {
+ return Integer.getInteger(propName, defaultValue);
+ }
+ else
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<Integer>()
+ {
+ public Integer run()
+ {
+ return Integer.getInteger(propName, defaultValue);
+ }
+ });
+ }
+ }
+
+ static Integer getInteger(final String propName)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null)
+ {
+ return Integer.getInteger(propName);
+ }
+ else
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<Integer>()
+ {
+ public Integer run()
+ {
+ return Integer.getInteger(propName);
+ }
+ });
+ }
+ }
+
/**
* Load a class using the provided classloader
*
Modified: stack/cxf/trunk/modules/testsuite/pom.xml
===================================================================
--- stack/cxf/trunk/modules/testsuite/pom.xml 2015-03-30 15:11:57 UTC (rev 19609)
+++ stack/cxf/trunk/modules/testsuite/pom.xml 2015-04-01 20:33:19 UTC (rev 19610)
@@ -314,7 +314,7 @@
<javax.net.ssl.keyStore>${project.build.directory}/test-classes/client.keystore</javax.net.ssl.keyStore>
<javax.net.ssl.keyStorePassword>changeit</javax.net.ssl.keyStorePassword>
<javax.net.ssl.keyStoreType>jks</javax.net.ssl.keyStoreType>
-
<org.jboss.security.ignoreHttpsHost>true</org.jboss.security.ignoreHttpsHost>
+
<cxf.tls-client.disableCNCheck>true</cxf.tls-client.disableCNCheck>
<jboss.home>${jboss.home}</jboss.home>
<jbossws.integration.target>${jbossws.integration.target}</jbossws.integration.target>
<log4j.output.dir>${log4j.output.dir}</log4j.output.dir>
@@ -355,7 +355,7 @@
<javax.net.ssl.keyStore>${project.build.directory}/test-classes/client.keystore</javax.net.ssl.keyStore>
<javax.net.ssl.keyStorePassword>changeit</javax.net.ssl.keyStorePassword>
<javax.net.ssl.keyStoreType>jks</javax.net.ssl.keyStoreType>
-
<org.jboss.security.ignoreHttpsHost>true</org.jboss.security.ignoreHttpsHost>
+
<cxf.tls-client.disableCNCheck>true</cxf.tls-client.disableCNCheck>
<jboss.home>${jboss.home}</jboss.home>
<jbossws.integration.target>${jbossws.integration.target}</jbossws.integration.target>
<log4j.output.dir>${log4j.output.dir}</log4j.output.dir>