You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2013/01/22 15:18:00 UTC

svn commit: r1436942 - in /syncope/branches/1_0_X: build-tools/src/main/java/org/apache/syncope/buildtools/ build-tools/src/main/webapp/WEB-INF/ core/src/main/java/org/apache/syncope/core/init/ core/src/main/java/org/apache/syncope/core/propagation/ co...

Author: fmartelli
Date: Tue Jan 22 14:17:59 2013
New Revision: 1436942

URL: http://svn.apache.org/viewvc?rev=1436942&view=rev
Log:
SYNCOPE-279 - Provided connector request timeout on 1_0_X

Added:
    syncope/branches/1_0_X/build-tools/src/main/java/org/apache/syncope/buildtools/ServiceTimeoutServlet.java   (with props)
    syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/AsyncConnectorFacade.java   (with props)
    syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/TimeoutException.java   (with props)
Modified:
    syncope/branches/1_0_X/build-tools/src/main/webapp/WEB-INF/web.xml
    syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/init/ConnInstanceLoader.java
    syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java
    syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/PropagationManager.java
    syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ConnInstanceController.java
    syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ResourceController.java
    syncope/branches/1_0_X/core/src/main/resources/content.xml
    syncope/branches/1_0_X/core/src/main/resources/securityContext.xml
    syncope/branches/1_0_X/core/src/main/resources/syncopeContext.xml
    syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/init/ConnInstanceLoaderTest.java
    syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
    syncope/branches/1_0_X/core/src/test/resources/content.xml

Added: syncope/branches/1_0_X/build-tools/src/main/java/org/apache/syncope/buildtools/ServiceTimeoutServlet.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/build-tools/src/main/java/org/apache/syncope/buildtools/ServiceTimeoutServlet.java?rev=1436942&view=auto
==============================================================================
--- syncope/branches/1_0_X/build-tools/src/main/java/org/apache/syncope/buildtools/ServiceTimeoutServlet.java (added)
+++ syncope/branches/1_0_X/build-tools/src/main/java/org/apache/syncope/buildtools/ServiceTimeoutServlet.java Tue Jan 22 14:17:59 2013
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.buildtools;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Just used to verify a connector request timeout.
+ */
+public class ServiceTimeoutServlet extends HttpServlet {
+
+    /**
+     * Processes requests for both HTTP
+     * <code>GET</code> and
+     * <code>POST</code> methods.
+     *
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+        response.setContentType("text/html;charset=UTF-8");
+
+        try {
+            Thread.sleep(60000);
+        } catch (InterruptedException ignore) {
+            // ignore
+        }
+
+        final PrintWriter out = response.getWriter();
+
+        try {
+            out.println("OK");
+        } finally {
+            out.close();
+        }
+    }
+
+    /**
+     * Handles the HTTP
+     * <code>GET</code> method.
+     *
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+        processRequest(request, response);
+    }
+
+    /**
+     * Handles the HTTP
+     * <code>POST</code> method.
+     *
+     * @param request servlet request
+     * @param response servlet response
+     * @throws ServletException if a servlet-specific error occurs
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    protected void doPost(HttpServletRequest request, HttpServletResponse response)
+            throws ServletException, IOException {
+        processRequest(request, response);
+    }
+
+    /**
+     * Returns a short description of the servlet.
+     *
+     * @return a String containing servlet description
+     */
+    @Override
+    public String getServletInfo() {
+        return "Service Timeout";
+    }
+}

Propchange: syncope/branches/1_0_X/build-tools/src/main/java/org/apache/syncope/buildtools/ServiceTimeoutServlet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_0_X/build-tools/src/main/java/org/apache/syncope/buildtools/ServiceTimeoutServlet.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_0_X/build-tools/src/main/java/org/apache/syncope/buildtools/ServiceTimeoutServlet.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_0_X/build-tools/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/build-tools/src/main/webapp/WEB-INF/web.xml?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/build-tools/src/main/webapp/WEB-INF/web.xml (original)
+++ syncope/branches/1_0_X/build-tools/src/main/webapp/WEB-INF/web.xml Tue Jan 22 14:17:59 2013
@@ -44,8 +44,16 @@ under the License.
         <servlet-name>ApacheDSRootDseServlet</servlet-name>
         <servlet-class>org.apache.syncope.buildtools.ApacheDSRootDseServlet</servlet-class>
     </servlet>
+    <servlet>
+        <servlet-name>ServiceTimeoutServlet</servlet-name>
+        <servlet-class>org.apache.syncope.buildtools.ServiceTimeoutServlet</servlet-class>
+    </servlet>
     <servlet-mapping>
         <servlet-name>ApacheDSRootDseServlet</servlet-name>
         <url-pattern>/apacheDS</url-pattern>
     </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>ServiceTimeoutServlet</servlet-name>
+        <url-pattern>/services/*</url-pattern>
+    </servlet-mapping>
 </web-app>

Modified: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/init/ConnInstanceLoader.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/init/ConnInstanceLoader.java?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/init/ConnInstanceLoader.java (original)
+++ syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/init/ConnInstanceLoader.java Tue Jan 22 14:17:59 2013
@@ -110,7 +110,8 @@ public class ConnInstanceLoader {
 
         connInstanceClone.setConfiguration(configuration);
 
-        return new ConnectorFacadeProxy(connInstanceClone, connBundleManager);
+        return getBeanFactory().getBean(
+                "connectorFacadeProxy", ConnectorFacadeProxy.class, connInstanceClone, connBundleManager);
     }
 
     public void registerConnector(final ExternalResource resource)
@@ -150,6 +151,7 @@ public class ConnInstanceLoader {
             }
         }
 
-        LOG.info("Done loading {} connectors.", getBeanFactory().getBeansOfType(ConnectorFacadeProxy.class).size());
+        LOG.info("Done loading {} connectors.", 
+                getBeanFactory().getBeansOfType(ConnectorFacadeProxy.class, false, true).size());
     }
 }

Added: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/AsyncConnectorFacade.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/AsyncConnectorFacade.java?rev=1436942&view=auto
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/AsyncConnectorFacade.java (added)
+++ syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/AsyncConnectorFacade.java Tue Jan 22 14:17:59 2013
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.propagation;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Future;
+import org.identityconnectors.framework.api.ConnectorFacade;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeInfo;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.identityconnectors.framework.common.objects.ObjectClassInfo;
+import org.identityconnectors.framework.common.objects.OperationOptions;
+import org.identityconnectors.framework.common.objects.OperationalAttributes;
+import org.identityconnectors.framework.common.objects.ResultsHandler;
+import org.identityconnectors.framework.common.objects.Schema;
+import org.identityconnectors.framework.common.objects.SyncDeltaBuilder;
+import org.identityconnectors.framework.common.objects.SyncDeltaType;
+import org.identityconnectors.framework.common.objects.SyncResultsHandler;
+import org.identityconnectors.framework.common.objects.SyncToken;
+import org.identityconnectors.framework.common.objects.Uid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.AsyncResult;
+
+/**
+ * Intercept calls to ConnectorFacade's methods and check if the corresponding connector instance has been configured to
+ * allow every single operation: if not, simply do nothing.
+ */
+public class AsyncConnectorFacade {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(AsyncConnectorFacade.class);
+
+    @Async
+    public Future<Uid> create(
+            final ConnectorFacade connector,
+            final ObjectClass objectClass,
+            final Set<Attribute> attrs,
+            final OperationOptions options) {
+
+        return new AsyncResult<Uid>(connector.create(objectClass, attrs, options));
+    }
+
+    @Async
+    public Future<Uid> update(
+            final ConnectorFacade connector,
+            final ObjectClass objectClass,
+            final Uid uid,
+            final Set<Attribute> attrs,
+            final OperationOptions options) {
+
+        return new AsyncResult<Uid>(connector.update(objectClass, uid, attrs, options));
+    }
+
+    @Async
+    public Future<Uid> delete(
+            final ConnectorFacade connector,
+            final ObjectClass objectClass,
+            final Uid uid,
+            final OperationOptions options) {
+
+        connector.delete(objectClass, uid, options);
+        return new AsyncResult<Uid>(uid);
+    }
+
+    @Async
+    public Future<SyncResultsHandler> sync(
+            final ConnectorFacade connector,
+            final SyncToken token,
+            final SyncResultsHandler handler,
+            final OperationOptions options) {
+
+        connector.sync(ObjectClass.ACCOUNT, token, handler, options);
+        return new AsyncResult<SyncResultsHandler>(handler);
+    }
+
+    @Async
+    public Future<SyncToken> getLatestSyncToken(
+            final ConnectorFacade connector) {
+
+        return new AsyncResult<SyncToken>(connector.getLatestSyncToken(ObjectClass.ACCOUNT));
+    }
+
+    @Async
+    public Future<ConnectorObject> getObject(
+            final ConnectorFacade connector,
+            final ObjectClass objectClass,
+            final Uid uid,
+            final OperationOptions options) {
+
+        return new AsyncResult<ConnectorObject>(connector.getObject(objectClass, uid, options));
+    }
+
+    @Async
+    public Future<SyncResultsHandler> getAllObjects(
+            final ConnectorFacade connector,
+            final ObjectClass objectClass,
+            final SyncResultsHandler handler,
+            final OperationOptions options) {
+
+        connector.search(objectClass, null, new ResultsHandler() {
+
+            @Override
+            public boolean handle(final ConnectorObject obj) {
+                final SyncDeltaBuilder bld = new SyncDeltaBuilder();
+                bld.setObject(obj);
+                bld.setUid(obj.getUid());
+                bld.setDeltaType(SyncDeltaType.CREATE_OR_UPDATE);
+                bld.setToken(new SyncToken(""));
+
+                return handler.handle(bld.build());
+            }
+        }, options);
+
+        return new AsyncResult<SyncResultsHandler>(handler);
+    }
+
+    @Async
+    public Future<Attribute> getObjectAttribute(
+            final ConnectorFacade connector,
+            final ObjectClass objectClass,
+            final Uid uid,
+            final OperationOptions options,
+            final String attributeName) {
+
+        Attribute attribute = null;
+
+        try {
+            final ConnectorObject object = connector.getObject(objectClass, uid, options);
+            attribute = object.getAttributeByName(attributeName);
+        } catch (NullPointerException e) {
+            // ignore exception
+            LOG.debug("Object for '{}' not found", uid.getUidValue());
+        }
+
+        return new AsyncResult<Attribute>(attribute);
+    }
+
+    @Async
+    public Future<Set<Attribute>> getObjectAttributes(
+            final ConnectorFacade connector,
+            final ObjectClass objectClass,
+            final Uid uid,
+            final OperationOptions options) {
+
+        final Set<Attribute> attributes = new HashSet<Attribute>();
+
+        try {
+            final ConnectorObject object = connector.getObject(objectClass, uid, options);
+
+            for (String attribute : options.getAttributesToGet()) {
+                attributes.add(object.getAttributeByName(attribute));
+            }
+        } catch (NullPointerException e) {
+            // ignore exception
+            LOG.debug("Object for '{}' not found", uid.getUidValue());
+        }
+
+        return new AsyncResult<Set<Attribute>>(attributes);
+    }
+
+    @Async
+    public Future<Set<String>> getSchema(
+            final ConnectorFacade connector,
+            final boolean showall) {
+        final Set<String> resourceSchemaNames = new HashSet<String>();
+
+        final Schema schema = connector.schema();
+
+        try {
+            for (ObjectClassInfo info : schema.getObjectClassInfo()) {
+                for (AttributeInfo attrInfo : info.getAttributeInfo()) {
+                    if (showall
+                            || (!Name.NAME.equals(attrInfo.getName())
+                            && !OperationalAttributes.PASSWORD_NAME.equals(attrInfo.getName()) && !OperationalAttributes.ENABLE_NAME.
+                            equals(attrInfo.getName()))) {
+
+                        resourceSchemaNames.add(attrInfo.getName());
+                    }
+                }
+            }
+        } catch (Exception e) {
+            // catch exception in order to manage unpredictable behaviors
+            LOG.debug("Unsupported operation {}", e);
+        }
+
+        return new AsyncResult<Set<String>>(resourceSchemaNames);
+    }
+
+    @Async
+    public Future<String> validate(final ConnectorFacade connector) {
+        connector.validate();
+        return new AsyncResult<String>("OK");
+    }
+
+    @Async
+    public Future<String> test(final ConnectorFacade connector) {
+        connector.test();
+        return new AsyncResult<String>("OK");
+    }
+}

Propchange: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/AsyncConnectorFacade.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/AsyncConnectorFacade.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/AsyncConnectorFacade.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java (original)
+++ syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/ConnectorFacadeProxy.java Tue Jan 22 14:17:59 2013
@@ -24,10 +24,15 @@ import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
 import javassist.NotFoundException;
 import org.apache.syncope.core.persistence.beans.ConnInstance;
 import org.apache.syncope.core.persistence.beans.ExternalResource;
 import org.apache.syncope.core.persistence.beans.SchemaMapping;
+import org.apache.syncope.core.persistence.dao.ConfDAO;
 import org.apache.syncope.core.persistence.dao.MissingConfKeyException;
 import org.apache.syncope.core.util.ConnBundleManager;
 import org.apache.syncope.core.util.SchemaMappingUtil;
@@ -44,23 +49,18 @@ import org.identityconnectors.framework.
 import org.identityconnectors.framework.api.ConnectorInfo;
 import org.identityconnectors.framework.api.ConnectorKey;
 import org.identityconnectors.framework.common.objects.Attribute;
-import org.identityconnectors.framework.common.objects.AttributeInfo;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
 import org.identityconnectors.framework.common.objects.Name;
 import org.identityconnectors.framework.common.objects.ObjectClass;
-import org.identityconnectors.framework.common.objects.ObjectClassInfo;
 import org.identityconnectors.framework.common.objects.OperationOptions;
 import org.identityconnectors.framework.common.objects.OperationOptionsBuilder;
 import org.identityconnectors.framework.common.objects.OperationalAttributes;
-import org.identityconnectors.framework.common.objects.ResultsHandler;
-import org.identityconnectors.framework.common.objects.Schema;
-import org.identityconnectors.framework.common.objects.SyncDeltaBuilder;
-import org.identityconnectors.framework.common.objects.SyncDeltaType;
 import org.identityconnectors.framework.common.objects.SyncResultsHandler;
 import org.identityconnectors.framework.common.objects.SyncToken;
 import org.identityconnectors.framework.common.objects.Uid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.ClassUtils;
 import org.springframework.util.StringUtils;
 
@@ -87,6 +87,23 @@ public class ConnectorFacadeProxy {
      */
     private final ConnInstance activeConnInstance;
 
+    private int timeout;
+
+    @Autowired
+    private AsyncConnectorFacade asyncFacade;
+
+    @Autowired
+    private ConfDAO confDAO;
+
+    @Autowired
+    private void setTimeout() {
+        try {
+            timeout = Integer.parseInt(confDAO.find("connectorRequest.timeout", "60").getValue());
+        } catch (Throwable t) {
+            timeout = 60;
+        }
+    }
+
     /**
      * Use the passed connector instance to build a ConnectorFacade that will be used to make all wrapped calls.
      *
@@ -187,7 +204,20 @@ public class ConnectorFacadeProxy {
 
             propagationAttempted.add("create");
 
-            result = connector.create(objectClass, attrs, options);
+            final Future<Uid> future = asyncFacade.create(connector, objectClass, attrs, options);
+            try {
+                result = future.get(timeout, TimeUnit.SECONDS);
+            } catch (java.util.concurrent.TimeoutException e) {
+                throw new TimeoutException("Request timeout");
+            } catch (Exception e) {
+                LOG.error("Connector request execution failure", e);
+                if (e.getCause() instanceof RuntimeException) {
+                    throw (RuntimeException) e.getCause();
+                } else {
+                    throw new IllegalArgumentException(e.getCause());
+                }
+            }
+
         } else {
             LOG.info("Create was attempted, although the " + "connector only has these capabilities: {}. No action.",
                     activeConnInstance.getCapabilities());
@@ -218,7 +248,21 @@ public class ConnectorFacadeProxy {
 
             propagationAttempted.add("update");
 
-            result = connector.update(objectClass, uid, attrs, options);
+            final Future<Uid> future = asyncFacade.update(connector, objectClass, uid, attrs, options);
+
+            try {
+                result = future.get(timeout, TimeUnit.SECONDS);
+            } catch (java.util.concurrent.TimeoutException e) {
+                throw new TimeoutException("Request timeout");
+            } catch (Exception e) {
+                LOG.error("Connector request execution failure", e);
+                if (e.getCause() instanceof RuntimeException) {
+                    throw (RuntimeException) e.getCause();
+                } else {
+                    throw new IllegalArgumentException(e.getCause());
+                }
+            }
+
         } else {
             LOG.info("Update for {} was attempted, although the "
                     + "connector only has these capabilities: {}. No action.", uid.getUidValue(), activeConnInstance.
@@ -246,7 +290,20 @@ public class ConnectorFacadeProxy {
 
             propagationAttempted.add("delete");
 
-            connector.delete(objectClass, uid, options);
+            final Future<Uid> future = asyncFacade.delete(connector, objectClass, uid, options);
+
+            try {
+                future.get(timeout, TimeUnit.SECONDS);
+            } catch (java.util.concurrent.TimeoutException e) {
+                throw new TimeoutException("Request timeout");
+            } catch (Exception e) {
+                LOG.error("Connector request execution failure", e);
+                if (e.getCause() instanceof RuntimeException) {
+                    throw (RuntimeException) e.getCause();
+                } else {
+                    throw new IllegalArgumentException(e.getCause());
+                }
+            }
         } else {
             LOG.info("Delete for {} was attempted, although the connector only has these capabilities: {}. No action.",
                     uid.getUidValue(), activeConnInstance.getCapabilities());
@@ -262,7 +319,21 @@ public class ConnectorFacadeProxy {
     public void sync(final SyncToken token, final SyncResultsHandler handler, final OperationOptions options) {
 
         if (activeConnInstance.getCapabilities().contains(ConnectorCapability.SYNC)) {
-            connector.sync(ObjectClass.ACCOUNT, token, handler, options);
+            final Future<SyncResultsHandler> future =
+                    asyncFacade.sync(connector, token, handler, options);
+
+            try {
+                // no timeout
+                future.get();
+            } catch (Exception e) {
+                LOG.error("Connector request execution failure", e);
+                if (e.getCause() instanceof RuntimeException) {
+                    throw (RuntimeException) e.getCause();
+                } else {
+                    throw new IllegalArgumentException(e.getCause());
+                }
+            }
+
         } else {
             LOG.info("Sync was attempted, although the connector only has these capabilities: {}. No action.",
                     activeConnInstance.getCapabilities());
@@ -278,7 +349,20 @@ public class ConnectorFacadeProxy {
         SyncToken result = null;
 
         if (activeConnInstance.getCapabilities().contains(ConnectorCapability.SYNC)) {
-            result = connector.getLatestSyncToken(ObjectClass.ACCOUNT);
+            final Future<SyncToken> future = asyncFacade.getLatestSyncToken(connector);
+
+            try {
+                result = future.get(timeout, TimeUnit.SECONDS);
+            } catch (java.util.concurrent.TimeoutException e) {
+                throw new TimeoutException("Request timeout");
+            } catch (Exception e) {
+                LOG.error("Connector request execution failure", e);
+                if (e.getCause() instanceof RuntimeException) {
+                    throw (RuntimeException) e.getCause();
+                } else {
+                    throw new IllegalArgumentException(e.getCause());
+                }
+            }
         } else {
             LOG.info("getLatestSyncToken was attempted, although the "
                     + "connector only has these capabilities: {}. No action.", activeConnInstance.getCapabilities());
@@ -314,11 +398,11 @@ public class ConnectorFacadeProxy {
     public ConnectorObject getObject(final PropagationMode propagationMode, final PropagationOperation operationType,
             final ObjectClass objectClass, final Uid uid, final OperationOptions options) {
 
-        ConnectorObject result = null;
+        Future<ConnectorObject> future = null;
 
         if (activeConnInstance.getCapabilities().contains(ConnectorCapability.SEARCH)) {
             if (operationType == null) {
-                result = connector.getObject(objectClass, uid, options);
+                future = asyncFacade.getObject(connector, objectClass, uid, options);
             } else {
                 switch (operationType) {
                     case CREATE:
@@ -326,7 +410,7 @@ public class ConnectorFacadeProxy {
                                 ? activeConnInstance.getCapabilities().contains(ConnectorCapability.ONE_PHASE_CREATE)
                                 : activeConnInstance.getCapabilities().contains(ConnectorCapability.TWO_PHASES_CREATE))) {
 
-                            result = connector.getObject(objectClass, uid, options);
+                            future = asyncFacade.getObject(connector, objectClass, uid, options);
                         }
                         break;
                     case UPDATE:
@@ -334,11 +418,11 @@ public class ConnectorFacadeProxy {
                                 ? activeConnInstance.getCapabilities().contains(ConnectorCapability.ONE_PHASE_UPDATE)
                                 : activeConnInstance.getCapabilities().contains(ConnectorCapability.TWO_PHASES_UPDATE))) {
 
-                            result = connector.getObject(objectClass, uid, options);
+                            future = asyncFacade.getObject(connector, objectClass, uid, options);
                         }
                         break;
                     default:
-                        result = connector.getObject(objectClass, uid, options);
+                        future = asyncFacade.getObject(connector, objectClass, uid, options);
                 }
             }
         } else {
@@ -346,7 +430,18 @@ public class ConnectorFacadeProxy {
                     activeConnInstance.getCapabilities());
         }
 
-        return result;
+        try {
+            return future == null ? null : future.get(timeout, TimeUnit.SECONDS);
+        } catch (java.util.concurrent.TimeoutException e) {
+            throw new TimeoutException("Request timeout");
+        } catch (Exception e) {
+            LOG.error("Connector request execution failure", e);
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            } else {
+                throw new IllegalArgumentException(e.getCause());
+            }
+        }
     }
 
     /**
@@ -361,19 +456,19 @@ public class ConnectorFacadeProxy {
             final OperationOptions options) {
 
         if (activeConnInstance.getCapabilities().contains(ConnectorCapability.SEARCH)) {
-            connector.search(objectClass, null, new ResultsHandler() {
-
-                @Override
-                public boolean handle(final ConnectorObject obj) {
-                    final SyncDeltaBuilder bld = new SyncDeltaBuilder();
-                    bld.setObject(obj);
-                    bld.setUid(obj.getUid());
-                    bld.setDeltaType(SyncDeltaType.CREATE_OR_UPDATE);
-                    bld.setToken(new SyncToken(""));
+            final Future<SyncResultsHandler> future = asyncFacade.getAllObjects(connector, objectClass, handler, options);
 
-                    return handler.handle(bld.build());
+            try {
+                // no timeout
+                future.get();
+            } catch (Exception e) {
+                LOG.error("Connector request execution failure", e);
+                if (e.getCause() instanceof RuntimeException) {
+                    throw (RuntimeException) e.getCause();
+                } else {
+                    throw new IllegalArgumentException(e.getCause());
                 }
-            }, options);
+            }
 
         } else {
             LOG.info("Search was attempted, although the connector only has these capabilities: {}. No action.",
@@ -396,12 +491,22 @@ public class ConnectorFacadeProxy {
         Attribute attribute = null;
 
         try {
-            final ConnectorObject object = connector.getObject(objectClass, uid, options);
+            final Future<Attribute> future =
+                    asyncFacade.getObjectAttribute(connector, objectClass, uid, options, attributeName);
 
-            attribute = object.getAttributeByName(attributeName);
+            attribute = future.get(timeout, TimeUnit.SECONDS);
         } catch (NullPointerException e) {
             // ignore exception
             LOG.debug("Object for '{}' not found", uid.getUidValue());
+        } catch (java.util.concurrent.TimeoutException e) {
+            throw new TimeoutException("Request timeout");
+        } catch (Exception e) {
+            LOG.error("Connector request execution failure", e);
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            } else {
+                throw new IllegalArgumentException(e.getCause());
+            }
         }
 
         return attribute;
@@ -421,14 +526,20 @@ public class ConnectorFacadeProxy {
         final Set<Attribute> attributes = new HashSet<Attribute>();
 
         try {
-            final ConnectorObject object = connector.getObject(objectClass, uid, options);
-
-            for (String attribute : options.getAttributesToGet()) {
-                attributes.add(object.getAttributeByName(attribute));
-            }
+            final Future<Set<Attribute>> future = asyncFacade.getObjectAttributes(connector, objectClass, uid, options);
+            attributes.addAll(future.get(timeout, TimeUnit.SECONDS));
         } catch (NullPointerException e) {
             // ignore exception
             LOG.debug("Object for '{}' not found", uid.getUidValue());
+        } catch (java.util.concurrent.TimeoutException e) {
+            throw new TimeoutException("Request timeout");
+        } catch (Exception e) {
+            LOG.error("Connector request execution failure", e);
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            } else {
+                throw new IllegalArgumentException(e.getCause());
+            }
         }
 
         return attributes;
@@ -443,40 +554,59 @@ public class ConnectorFacadeProxy {
     public Set<String> getSchema(final boolean showall) {
         final Set<String> resourceSchemaNames = new HashSet<String>();
 
-        final Schema schema = connector.schema();
+        final Future<Set<String>> future = asyncFacade.getSchema(connector, showall);
 
         try {
-            for (ObjectClassInfo info : schema.getObjectClassInfo()) {
-                for (AttributeInfo attrInfo : info.getAttributeInfo()) {
-                    if (showall
-                            || (!Name.NAME.equals(attrInfo.getName())
-                            && !OperationalAttributes.PASSWORD_NAME.equals(attrInfo.getName()) && !OperationalAttributes.ENABLE_NAME.
-                            equals(attrInfo.getName()))) {
-
-                        resourceSchemaNames.add(attrInfo.getName());
-                    }
-                }
-            }
+            resourceSchemaNames.addAll(future.get(timeout, TimeUnit.SECONDS));
+        } catch (java.util.concurrent.TimeoutException e) {
+            throw new TimeoutException("Request timeout");
         } catch (Exception e) {
-            // catch exception in order to manage unpredictable behaviors
-            LOG.debug("Unsupported operation {}", e);
+            LOG.error("Connector request execution failure", e);
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            } else {
+                throw new IllegalArgumentException(e.getCause());
+            }
         }
 
         return resourceSchemaNames;
+
     }
 
     /**
      * Validate a connector instance.
      */
     public void validate() {
-        connector.validate();
+        try {
+            asyncFacade.test(connector).get(timeout, TimeUnit.SECONDS);
+        } catch (java.util.concurrent.TimeoutException e) {
+            throw new TimeoutException("Request timeout");
+        } catch (Exception e) {
+            LOG.error("Connector request execution failure", e);
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            } else {
+                throw new IllegalArgumentException(e.getCause());
+            }
+        }
     }
 
     /**
      * Check connection to resource.
      */
     public void test() {
-        connector.test();
+        try {
+            asyncFacade.test(connector).get(timeout, TimeUnit.SECONDS);
+        } catch (java.util.concurrent.TimeoutException e) {
+            throw new TimeoutException("Request timeout");
+        } catch (Exception e) {
+            LOG.error("Connector request execution failure", e);
+            if (e.getCause() instanceof RuntimeException) {
+                throw (RuntimeException) e.getCause();
+            } else {
+                throw new IllegalArgumentException(e.getCause());
+            }
+        }
     }
 
     @Override

Modified: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/PropagationManager.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/PropagationManager.java?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/PropagationManager.java (original)
+++ syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/PropagationManager.java Tue Jan 22 14:17:59 2013
@@ -889,6 +889,9 @@ public class PropagationManager {
                     ? task.getAccountId()
                     : task.getOldAccountId()), connector.getOperationOptions(task.getResource()));
 
+        } catch (TimeoutException toe) {
+            LOG.debug("Request timeout", toe);
+            throw toe;
         } catch (RuntimeException ignore) {
             LOG.debug("Resolving username", ignore);
             return null;

Added: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/TimeoutException.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/TimeoutException.java?rev=1436942&view=auto
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/TimeoutException.java (added)
+++ syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/TimeoutException.java Tue Jan 22 14:17:59 2013
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.propagation;
+
+/**
+ *
+ * @author fabio
+ */
+public class TimeoutException extends RuntimeException {
+
+    /**
+     * Creates a new instance of
+     * <code>TimeoutException</code> without detail message.
+     */
+    public TimeoutException() {
+    }
+
+    /**
+     * Constructs an instance of
+     * <code>TimeoutException</code> with the specified detail message.
+     *
+     * @param msg the detail message.
+     */
+    public TimeoutException(String msg) {
+        super(msg);
+    }
+}

Propchange: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/TimeoutException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/TimeoutException.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/propagation/TimeoutException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ConnInstanceController.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ConnInstanceController.java?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ConnInstanceController.java (original)
+++ syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ConnInstanceController.java Tue Jan 22 14:17:59 2013
@@ -369,8 +369,8 @@ public class ConnInstanceController exte
     public ModelAndView check(final HttpServletResponse response, @RequestBody final ConnInstanceTO connectorTO)
             throws SyncopeClientCompositeErrorException, NotFoundException {
 
-        final ConnectorFacadeProxy connector = new ConnectorFacadeProxy(binder.getConnInstance(connectorTO),
-                bundleManager);
+        final ConnectorFacadeProxy connector =
+                connLoader.createConnectorBean(binder.getConnInstance(connectorTO), connectorTO.getConfiguration());
 
         boolean result;
         try {

Modified: syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ResourceController.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ResourceController.java?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ResourceController.java (original)
+++ syncope/branches/1_0_X/core/src/main/java/org/apache/syncope/core/rest/controller/ResourceController.java Tue Jan 22 14:17:59 2013
@@ -23,21 +23,6 @@ import java.util.List;
 import java.util.Set;
 import javassist.NotFoundException;
 import javax.servlet.http.HttpServletResponse;
-import org.identityconnectors.framework.common.objects.Attribute;
-import org.identityconnectors.framework.common.objects.AttributeUtil;
-import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.identityconnectors.framework.common.objects.Name;
-import org.identityconnectors.framework.common.objects.ObjectClass;
-import org.identityconnectors.framework.common.objects.Uid;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.stereotype.Controller;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
 import org.apache.syncope.client.to.ConnObjectTO;
 import org.apache.syncope.client.to.ResourceTO;
 import org.apache.syncope.client.to.SchemaMappingTO;
@@ -59,6 +44,21 @@ import org.apache.syncope.types.AuditEle
 import org.apache.syncope.types.AuditElements.Category;
 import org.apache.syncope.types.AuditElements.ResourceSubCategory;
 import org.apache.syncope.types.AuditElements.Result;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.identityconnectors.framework.common.objects.Uid;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Controller;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.servlet.ModelAndView;
 
 @Controller
@@ -261,7 +261,7 @@ public class ResourceController extends 
         final ConnInstance connInstance = binder.getConnInstance(resourceTO);
 
         final ConnectorFacadeProxy connector =
-                new ConnectorFacadeProxy(connInstance, bundleManager);
+                connLoader.createConnectorBean(connInstance, connInstance.getConfiguration());
 
         boolean result;
         try {

Modified: syncope/branches/1_0_X/core/src/main/resources/content.xml
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/resources/content.xml?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/resources/content.xml (original)
+++ syncope/branches/1_0_X/core/src/main/resources/content.xml Tue Jan 22 14:17:59 2013
@@ -26,6 +26,7 @@ under the License.
   <SyncopeConf confKey="connid.bundles.directory" confValue="${bundles.directory}"/>
   <SyncopeConf confKey="password.cipher.algorithm" confValue="MD5"/>
   <SyncopeConf confKey="createRequest.allowed" confValue="false"/>
+  <SyncopeConf confKey="connectorRequest.timeout" confValue="10"/>
     
   <Policy DTYPE="SyncPolicy" id="1" description="Global Sync Policy" type="GLOBAL_SYNC"
           specification="%3Corg.apache.syncope.types.SyncPolicySpec%2F%3E"/>

Modified: syncope/branches/1_0_X/core/src/main/resources/securityContext.xml
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/resources/securityContext.xml?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/resources/securityContext.xml (original)
+++ syncope/branches/1_0_X/core/src/main/resources/securityContext.xml Tue Jan 22 14:17:59 2013
@@ -51,4 +51,13 @@ under the License.
     <security:authentication-provider ref="syncopeAuthenticationProvider"/>
   </security:authentication-manager>
 
+  <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
+    <property name="targetClass" value="org.springframework.security.core.context.SecurityContextHolder"/> 
+    <property name="targetMethod" value="setStrategyName"/> 
+    <property name="arguments">
+      <list>
+        <value>MODE_INHERITABLETHREADLOCAL</value>
+      </list>
+    </property>
+  </bean>
 </beans>

Modified: syncope/branches/1_0_X/core/src/main/resources/syncopeContext.xml
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/main/resources/syncopeContext.xml?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/main/resources/syncopeContext.xml (original)
+++ syncope/branches/1_0_X/core/src/main/resources/syncopeContext.xml Tue Jan 22 14:17:59 2013
@@ -20,11 +20,14 @@ under the License.
 -->
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:task="http://www.springframework.org/schema/task"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
-                           http://www.springframework.org/schema/context/spring-context.xsd">
+                           http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/task
+                           http://www.springframework.org/schema/task/spring-task-3.1.xsd">
 
   <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
     <property name="locations">
@@ -69,7 +72,13 @@ under the License.
   <bean id="propagationManager" class="org.apache.syncope.core.propagation.PropagationManager"/>
   <bean id="notificationManager" class="org.apache.syncope.core.notification.NotificationManager"/>
   <bean id="auditManager" class="org.apache.syncope.core.audit.AuditManager"/>
-          
+  
+  <bean id="connectorFacadeProxy" class="org.apache.syncope.core.propagation.ConnectorFacadeProxy" scope="prototype"/>
+  <bean id="asyncConnFacade" class="org.apache.syncope.core.propagation.AsyncConnectorFacade" scope="singleton"/>
+  
+  <task:annotation-driven executor="connectorExecutor"/>
+  <task:executor id="connectorExecutor" pool-size="10"/>
+  
   <bean id="jexlEngine" class="org.apache.commons.jexl2.JexlEngine">
     <property name="cache" value="512"/>
     <property name="lenient" value="true"/>

Modified: syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/init/ConnInstanceLoaderTest.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/init/ConnInstanceLoaderTest.java?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/init/ConnInstanceLoaderTest.java (original)
+++ syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/init/ConnInstanceLoaderTest.java Tue Jan 22 14:17:59 2013
@@ -68,6 +68,6 @@ public class ConnInstanceLoaderTest exte
 
         assertEquals(resourceDAO.findAll().size(),
                 ApplicationContextProvider.getApplicationContext().
-                getBeanNamesForType(ConnectorFacadeProxy.class).length);
+                getBeanNamesForType(ConnectorFacadeProxy.class, false, true).length);
     }
 }

Modified: syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java (original)
+++ syncope/branches/1_0_X/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java Tue Jan 22 14:17:59 2013
@@ -2207,4 +2207,12 @@ public class UserTestITCase extends Abst
         userTO = restTemplate.postForObject(BASE_URL + "user/update", userMod, UserTO.class);
         assertNotNull(userTO);
     }
+
+    @Test(expected = SyncopeClientCompositeErrorException.class)
+    public void issueSYNCOPE279() {
+        UserTO userTO = getSampleTO("syncope260@apache.org");
+        userTO.getResources().clear();
+        userTO.addResource("ws-target-resource-3");
+        restTemplate.postForObject(BASE_URL + "user/create", userTO, UserTO.class);
+    }
 }

Modified: syncope/branches/1_0_X/core/src/test/resources/content.xml
URL: http://svn.apache.org/viewvc/syncope/branches/1_0_X/core/src/test/resources/content.xml?rev=1436942&r1=1436941&r2=1436942&view=diff
==============================================================================
--- syncope/branches/1_0_X/core/src/test/resources/content.xml (original)
+++ syncope/branches/1_0_X/core/src/test/resources/content.xml Tue Jan 22 14:17:59 2013
@@ -26,6 +26,7 @@ under the License.
   <SyncopeConf confKey="connid.bundles.directory" confValue="${bundles.directory}"/>
   <SyncopeConf confKey="password.cipher.algorithm" confValue="MD5"/>
   <SyncopeConf confKey="createRequest.allowed" confValue="true"/>
+  <SyncopeConf confKey="connectorRequest.timeout" confValue="10"/>
 
   <!-- sample policies -->
   <Policy DTYPE="SyncPolicy" id="1" description="sync policy 1" type="GLOBAL_SYNC" specification="%3Corg.apache.syncope.types.SyncPolicySpec%2F%3E"/>
@@ -335,6 +336,9 @@ under the License.
                     propagationPriority="0" propagationPrimary="1" createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" syncTraceLevel="ALL"/>
   <ExternalResource name="ws-target-resource-2" connector_id="100" forceMandatoryConstraint="1" propagationMode="TWO_PHASES"
                     propagationPriority="0" propagationPrimary="1" createTraceLevel="FAILURES" deleteTraceLevel="NONE" updateTraceLevel="ALL" syncTraceLevel="ALL"/>
+  <ExternalResource name="ws-target-resource-3" connector_id="102" forceMandatoryConstraint="0" propagationMode="TWO_PHASES"
+                    propagationPriority="0" propagationPrimary="1" createTraceLevel="FAILURES" deleteTraceLevel="NONE" updateTraceLevel="ALL" syncTraceLevel="ALL"
+                    xmlConfiguration="%3Cset%3E%0A++%3Corg.apache.syncope.types.ConnConfProperty%3E%0A++++%3Cschema%3E%0A++++++%3Cname%3Eendpoint%3C/name%3E%0A++++++%3Ctype%3Ejava.lang.String%3C/type%3E%0A++++++%3Crequired%3Etrue%3C/required%3E%0A++++%3C/schema%3E%0A++++%3Cvalues%3E%0A++++++%3Cjava.lang.String%3Ehttp%3A//localhost%3A9080/syncope-build-tools/services/provisioning%3C/java.lang.String%3E%0A++++%3C/values%3E%0A++++%3Coverridable%3Efalse%3C/overridable%3E%0A++%3C/org.apache.syncope.types.ConnConfProperty%3E%0A%3C/set%3E"/>
   <ExternalResource name="ws-target-resource-list-mappings-1" connector_id="100" forceMandatoryConstraint="0" propagationMode="TWO_PHASES"
                     propagationPriority="0" propagationPrimary="0" createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" syncTraceLevel="ALL"/>
   <ExternalResource name="ws-target-resource-list-mappings-2" connector_id="100" forceMandatoryConstraint="1" propagationMode="TWO_PHASES"
@@ -597,6 +601,11 @@ under the License.
   <SchemaMapping id="332" resource_name="resource-db-virattr" accountid="0" password="0" 
                  extAttrName="USERNAME" intAttrName="virtualdata" intMappingType="UserVirtualSchema"
                  mandatoryCondition="false" />
+                 
+  <SchemaMapping id="333"
+                 resource_name="ws-target-resource-3"
+                 intAttrName="fullname" intMappingType="UserSchema" mandatoryCondition="true"
+                 accountid="1" password="0"/>
   
   <Task DTYPE="PropagationTask" id="1" propagationMode="TWO_PHASES" propagationOperation="UPDATE"
         resource_name="ws-target-resource-2" syncopeUser_id="1"