blob: 036ea5b4941d07e7d8c11150be565a56db5997ae [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.server;
import java.io.Externalizable;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.rmi.Remote;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMISocketFactory;
import java.security.AccessControlException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.statet.rj.RjException;
import org.eclipse.statet.rj.data.RObjectFactory;
public class RjsComConfig {
public static final String RJ_COM_S2C_ID_PROPERTY_ID= "rj.com.s2c.id";
public static final String RJ_DATA_STRUCTS_LISTS_MAX_LENGTH_PROPERTY_ID= "rj.data.structs.lists.max_length";
public static final String RJ_DATA_STRUCTS_ENVS_MAX_LENGTH_PROPERTY_ID= "rj.data.structs.envs.max_length";
private static final Map<String, Object> PROPERTIES= new ConcurrentHashMap<>();
public static interface PathResolver {
File resolve(Remote client, String path) throws RjException;
}
public static void setServerPathResolver(final RjsComConfig.PathResolver resolver) {
BinExchange.gSPathResolver= resolver;
}
public static int registerClientComHandler(final ComHandler handler) {
if (handler == null) {
throw new NullPointerException();
}
final int id= MainCmdS2CList.gComHandlers.put(handler);
if (id < 0xffff) {
return id;
}
MainCmdS2CList.gComHandlers.remove(id);
throw new UnsupportedOperationException("Too much open clients");
}
public static void unregisterClientComHandler(final int id) {
MainCmdS2CList.gComHandlers.remove(id);
}
/**
* Registers an additional RObject factory
*
* Factory registration is valid for the current VM.
*/
public static final void registerRObjectFactory(final String id, final RObjectFactory factory) {
if (id == null || factory == null) {
throw new NullPointerException();
}
if (id.equals(DataCmdItem.DEFAULT_FACTORY_ID)) {
throw new IllegalArgumentException();
}
DataCmdItem.gFactories.put(id, factory);
}
/**
* Sets the default RObject factory
*
* Factory registration is valid for the current VM.
*/
public static final void setDefaultRObjectFactory(final RObjectFactory factory) {
if (factory == null) {
throw new NullPointerException();
}
DataCmdItem.gDefaultFactory= factory;
DataCmdItem.gFactories.put(DataCmdItem.DEFAULT_FACTORY_ID, factory);
}
public static final void setProperty(final String key, final Object value) {
PROPERTIES.put(key, value);
}
public static final Object getProperty(final String key) {
return PROPERTIES.get(key);
}
private static final ThreadLocal<RMIClientSocketFactory> gRMIClientSocketFactoriesInit= new ThreadLocal<>();
private static final ConcurrentHashMap<String, RMIClientSocketFactory> gRMIClientSocketFactories= new ConcurrentHashMap<>();
private static RMIClientSocketFactory getSystemRMIClientSocketFactory() {
RMIClientSocketFactory factory= RMISocketFactory.getSocketFactory();
if (factory == null) {
factory= RMISocketFactory.getDefaultSocketFactory();
}
return factory;
}
private static final class RjRMIClientSocketFactory implements RMIClientSocketFactory, Externalizable {
private static final long serialVersionUID= -2470426070934072117L;
private static String getLocalHostName() {
try {
return InetAddress.getLocalHost().getCanonicalHostName();
}
catch (final UnknownHostException e) {}
catch (final ArrayIndexOutOfBoundsException e) { /* JVM bug */ }
return "unknown";
}
private String id;
private RMIClientSocketFactory resolvedFactory;
public RjRMIClientSocketFactory() {
}
public RjRMIClientSocketFactory(final String init) {
final StringBuilder sb= new StringBuilder(init);
sb.append(getLocalHostName());
sb.append('/').append(System.nanoTime()).append('/').append(Math.random());
this.id= sb.toString();
}
@Override
public void writeExternal(final ObjectOutput out) throws IOException {
out.writeUTF(this.id);
}
@Override
public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
this.id= in.readUTF();
}
@Override
public Socket createSocket(final String host, final int port) throws IOException {
RMIClientSocketFactory factory= null;
factory= gRMIClientSocketFactoriesInit.get();
if (factory != null) {
this.resolvedFactory= factory;
gRMIClientSocketFactories.put(this.id, factory);
}
else {
factory= this.resolvedFactory;
if (factory == null) {
factory= gRMIClientSocketFactories.get(this.id);
if (factory != null) {
this.resolvedFactory= factory;
}
else {
factory= getSystemRMIClientSocketFactory();
}
}
}
return factory.createSocket(host, port);
}
@Override
public int hashCode() {
return this.id.hashCode();
}
@Override
public boolean equals(final Object obj) {
return (this == obj
|| (obj instanceof RjRMIClientSocketFactory
&& this.id.equals(((RjRMIClientSocketFactory) obj).id) ));
}
}
private final static boolean RMISERVER_CLIENTSOCKET_FACTORY_ENABLED;
private static RMIClientSocketFactory RMISERVER_CLIENTSOCKET_FACTORY;
static {
{ boolean enabled= true;
try {
if ("true".equalsIgnoreCase(System.getProperty("org.eclipse.statet.rj.rmi.disableSocketFactory"))) {
enabled= false;
}
}
catch (final AccessControlException e) { // in RMI registry
}
RMISERVER_CLIENTSOCKET_FACTORY_ENABLED= enabled;
}
}
public static synchronized final RMIClientSocketFactory getRMIServerClientSocketFactory() {
if (RMISERVER_CLIENTSOCKET_FACTORY_ENABLED && RMISERVER_CLIENTSOCKET_FACTORY == null) {
RMISERVER_CLIENTSOCKET_FACTORY= new RjRMIClientSocketFactory("S/");
}
return RMISERVER_CLIENTSOCKET_FACTORY;
}
public static final void setRMIClientSocketFactory(RMIClientSocketFactory factory) {
if (factory == null) {
factory= getSystemRMIClientSocketFactory();
}
gRMIClientSocketFactoriesInit.set(factory);
}
public static final void clearRMIClientSocketFactory() {
gRMIClientSocketFactoriesInit.set(null);
}
}