001/*
002 * (C) Copyright 2006-2010 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     bstefanescu
018 */
019package org.nuxeo.ecm.automation.client.jaxrs.spi;
020
021import java.util.concurrent.ExecutorService;
022import java.util.concurrent.Executors;
023import java.util.concurrent.ThreadFactory;
024import java.util.concurrent.TimeUnit;
025
026import org.nuxeo.ecm.automation.client.AdapterFactory;
027import org.nuxeo.ecm.automation.client.AdapterManager;
028import org.nuxeo.ecm.automation.client.AutomationClient;
029import org.nuxeo.ecm.automation.client.LoginCallback;
030import org.nuxeo.ecm.automation.client.LoginInfo;
031import org.nuxeo.ecm.automation.client.Session;
032
033/**
034 * Abstract class for clients running on real JVMs.
035 * <p>
036 * When your implementation is designed for running in environment that supports limited Java API like GWT or portable
037 * devices you may need to directly implement the {@link AutomationClient} interface.
038 *
039 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
040 */
041public abstract class JavaClient implements AutomationClient {
042
043    protected String url;
044
045    protected AdapterManager adapters;
046
047    protected ExecutorService async;
048
049    protected JavaClient(String url) {
050        this(url, null);
051    }
052
053    public JavaClient(String url, ExecutorService executor) {
054        this.url = url.endsWith("/") ? url : url + "/";
055        this.async = executor == null ? Executors.newCachedThreadPool(new ThreadFactory() {
056            public Thread newThread(Runnable r) {
057                return new Thread("AutomationAsyncExecutor");
058            }
059        }) : executor;
060    }
061
062    /**
063     * Validate the credentials. The login must occurs in first place before a session is created. A stateless session
064     * may login each time using these credentials but you canot get a session without login-in first.
065     *
066     * @param username
067     * @param password
068     * @return
069     */
070    protected abstract LoginInfo login(String username, String password);
071
072    /**
073     * Create a valid session using the authenticated login. The session will download any required data like the
074     * operation registry before being usable.
075     *
076     * @param login
077     * @return
078     */
079    protected abstract JavaSession createSession(LoginInfo login);
080
081    @Override
082    public String getBaseUrl() {
083        return url;
084    }
085
086    public AdapterManager getAdapterManager() {
087        return adapters;
088    }
089
090    public void asyncExec(Runnable runnable) {
091        async.execute(runnable);
092    }
093
094    @Override
095    public <T> T getAdapter(Session session, Class<T> adapterType) {
096        return adapters.getAdapter(session, adapterType);
097    }
098
099    @Override
100    public void registerAdapter(AdapterFactory<?> factory) {
101        adapters.registerAdapter(factory);
102    }
103
104    @Override
105    public Session getSession(LoginCallback cb) {
106        String[] login = cb.getLogin();
107        return getSession(login[0], login[1]);
108    }
109
110    @Override
111    public Session getSession(String username, String password) {
112        LoginInfo login = login(username, password);
113        if (login == null) {
114            throw new RuntimeException("Failed to login as " + username);
115        }
116        return createSession(login);
117    }
118
119    @Override
120    public Session getSession() {
121        return getSession((String) null, (String) null);
122    }
123
124    @Override
125    public void shutdown() {
126        shutdown(500);
127    }
128
129    /**
130     * TODO Move this in interface?
131     *
132     * @param timeout
133     */
134    public void shutdown(long timeout) {
135        try {
136            async.awaitTermination(timeout, TimeUnit.MILLISECONDS);
137        } catch (InterruptedException e) {
138            // do nothing - TODO: log?
139        } finally {
140            async = null;
141            url = null;
142            adapters = null;
143        }
144    }
145
146}