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