/**
* GRANITE DATA SERVICES
* Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S.
*
* This file is part of the Granite Data Services Platform.
*
* Granite Data Services is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Granite Data Services is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA, or see <http://www.gnu.org/licenses/>.
*/
package org.granite.client.platform;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.granite.client.configuration.Configuration;
import org.granite.client.configuration.ClassScanner;
import org.granite.client.messaging.channel.ChannelType;
import org.granite.client.messaging.transport.Transport;
import org.granite.client.persistence.Persistence;
import org.granite.logging.Logger;
import org.granite.messaging.reflect.Reflection;
import org.granite.util.ServiceLoader;
import org.granite.util.TypeUtil;
/**
* Platform abstracts everything specific to a target framework or platform
*
* Implementations are looked for in the {@link java.util.ServiceLoader} registry.
* The platform implementation must be unique (otherwise a PlatformConfigurationError is throws). To resolve the ambiguity,
* the platform class name can also be defined by the system property org.granite.client.platform.Platform.
*
* @author Franck WOLFF
*/
public class Platform {
private static final Logger log = Logger.getLogger(Platform.class);
public static final String SYSTEM_PROPERTY_KEY = Platform.class.getName();
protected static Platform instance = null;
protected final Reflection reflection;
protected final Persistence persistence;
protected Object context;
public static synchronized Platform getInstance() {
if (instance == null) {
String platformClassName = System.getProperty(SYSTEM_PROPERTY_KEY);
if (platformClassName == null)
initInstance((ClassLoader)null);
if (instance == null)
initInstance(platformClassName, null);
}
return instance;
}
public static synchronized Platform initInstance(ClassLoader platformClassLoader) {
if (instance != null)
throw new IllegalStateException("Platform already loaded");
if (platformClassLoader == null)
platformClassLoader = Thread.currentThread().getContextClassLoader();
ServiceLoader<Platform> platformLoader = ServiceLoader.load(Platform.class, platformClassLoader);
Iterator<Platform> platforms = null;
try {
platforms = platformLoader.iterator();
if (platforms.hasNext())
instance = platforms.next();
if (platforms.hasNext())
throw new PlatformConfigurationError("Multiple Platform services: " + instance + " / " + platforms.next());
}
catch (PlatformConfigurationError e) {
throw e;
}
catch (Throwable t) {
throw new PlatformConfigurationError("Could not load Platform service", t);
}
return instance;
}
public static synchronized Platform initInstance(String platformClassName) {
return initInstance(platformClassName, null);
}
public static synchronized Platform initInstance(String platformClassName, ClassLoader platformClassLoader) {
return initInstance(platformClassName, platformClassLoader, null);
}
public static synchronized Platform initInstance(String platformClassName, ClassLoader platformClassLoader, ClassLoader reflectionClassLoader) {
if (instance != null)
throw new IllegalStateException("Platform already loaded");
if (platformClassLoader == null)
platformClassLoader = Thread.currentThread().getContextClassLoader();
if (platformClassName == null)
platformClassName = Platform.class.getName();
try {
@SuppressWarnings("unchecked")
Class<? extends Platform> platformClass = (Class<? extends Platform>)platformClassLoader.loadClass(platformClassName);
instance = platformClass.getConstructor(ClassLoader.class).newInstance(reflectionClassLoader);
}
catch (Throwable t) {
throw new PlatformConfigurationError("Could not create new Platform of type: " + platformClassName, t);
}
return instance;
}
public Platform() {
this(new Reflection(null));
}
public Platform(ClassLoader reflectionClassLoader) {
this(new Reflection(reflectionClassLoader));
}
public Platform(Reflection reflection) {
if (reflection == null)
throw new NullPointerException("reflection cannot be null");
this.reflection = reflection;
this.persistence = new Persistence(reflection);
}
public Object getContext() {
return context;
}
public void setContext(Object context) {
this.context = context;
}
public ClassScanner newClassScanner() {
String scannerClassName = System.getProperty("scanner.className");
if (scannerClassName != null) {
try {
return TypeUtil.newInstance(scannerClassName, ClassScanner.class);
}
catch (Throwable t) {
throw new RuntimeException("Specified scanner class " + scannerClassName + " not available", t);
}
}
try {
return TypeUtil.newInstance("org.granite.client.scan.ExtCosClassScanner", ClassScanner.class);
}
catch (Throwable t) {
log.debug(t, "Extcos scanner not available, using classpath scanner");
}
try {
return TypeUtil.newInstance("org.granite.client.scan.StandardClassScanner", ClassScanner.class);
}
catch (Throwable t) {
throw new RuntimeException("Could not create class scanner", t);
}
}
public Reflection getReflection() {
return reflection;
}
public Configuration newConfiguration() {
try {
return TypeUtil.newInstance("org.granite.client.configuration.SimpleConfiguration", Configuration.class);
}
catch (Throwable t) {
throw new RuntimeException("Could not create simple configuration", t);
}
}
public String defaultChannelType() {
return ChannelType.LONG_POLLING;
}
public Transport newRemotingTransport() {
try {
return TypeUtil.newInstance("org.granite.client.messaging.transport.apache.ApacheAsyncTransport", Transport.class);
}
catch (Exception e) {
throw new RuntimeException("Could not create Apache transport");
}
}
public Transport newMessagingTransport() {
return null;
}
public Map<String, Transport> getMessagingTransports() {
Map<String, Transport> transportMap = new HashMap<String, Transport>();
try {
TypeUtil.forName("org.eclipse.jetty.websocket.jsr356.JettyClientContainerProvider");
transportMap.put(ChannelType.WEBSOCKET, TypeUtil.newInstance("org.granite.client.messaging.transport.jetty9.JettyStdWebSocketTransport", Transport.class));
}
catch (Throwable e1) {
try {
TypeUtil.forName("org.eclipse.jetty.websocket.client.WebSocketClient");
transportMap.put(ChannelType.WEBSOCKET, TypeUtil.newInstance("org.granite.client.messaging.transport.jetty9.JettyStdWebSocketTransport", Transport.class));
}
catch (Throwable e2) {
// Jetty 9 websocket client not found
try {
TypeUtil.forName("org.eclipse.jetty.websocket.WebSocketClientFactory");
transportMap.put(ChannelType.WEBSOCKET, TypeUtil.newInstance("org.granite.client.messaging.transport.jetty.JettyWebSocketTransport", Transport.class));
}
catch (Throwable e3) {
// Jetty 8 websocket client not found
try {
TypeUtil.forName("org.glassfish.tyrus.client.ClientManager");
transportMap.put(ChannelType.WEBSOCKET, TypeUtil.newInstance("org.granite.client.messaging.transport.tyrus.TyrusWebSocketTransport", Transport.class));
}
catch (Throwable e4) {
// Tyrus websocket client not found
}
}
}
}
return transportMap;
}
public Persistence getPersistence() {
return persistence;
}
public static Reflection reflection() {
return getInstance().reflection;
}
public static Persistence persistence() {
return getInstance().persistence;
}
}