blob: de8a65b4fb5e85956ea794bd86776ef2a1ec561b [file] [log] [blame]
/*
* 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 com.gemstone.gemfire;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.geode.cache.Cache;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.internal.InternalDataSerializer;
import org.apache.geode.internal.cache.CacheService;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.tier.sockets.OldClientSupportService;
import org.apache.geode.internal.serialization.Version;
import org.apache.geode.internal.serialization.VersionedDataOutputStream;
import org.apache.geode.management.internal.beans.CacheServiceMBeanBase;
import com.gemstone.gemfire.cache.execute.EmtpyRegionFunctionException;
/**
* Support for old GemFire clients
*/
public class OldClientSupportProvider implements OldClientSupportService {
static final String GEODE = "org.apache.geode";
static final String GEMFIRE = "com.gemstone.gemfire";
static final String ALWAYS_CONVERT_CLASSES_NAME =
DistributionConfig.GEMFIRE_PREFIX + "old-client-support.convert-all";
/** whether to always convert new package names to old on outgoing serialization */
static final boolean ALWAYS_CONVERT_CLASSES = Boolean.getBoolean(ALWAYS_CONVERT_CLASSES_NAME);
private final Map<String, String> oldClassNamesToNew = new ConcurrentHashMap<>();
private final Map<String, String> newClassNamesToOld = new ConcurrentHashMap<>();
/** returns the cache's OldClientSupportService */
public static OldClientSupportService getService(Cache cache) {
return (OldClientSupportService) ((InternalCache) cache)
.getService(OldClientSupportService.class);
}
@Override
public boolean init(final Cache cache) {
InternalDataSerializer.setOldClientSupportService(this);
return true;
}
@Override
public Class<? extends CacheService> getInterface() {
return OldClientSupportService.class;
}
@Override
public CacheServiceMBeanBase getMBean() {
// no mbean services provided
return null;
}
@Override
public String processIncomingClassName(String name) {
// tcpserver was moved to a different package in Geode.
String oldPackage = "com.gemstone.org.jgroups.stack.tcpserver";
String newPackage = "org.apache.geode.distributed.internal.tcpserver";
if (name.startsWith(oldPackage)) {
String cached = oldClassNamesToNew.get(name);
if (cached == null) {
cached = newPackage + name.substring(oldPackage.length());
oldClassNamesToNew.put(name, cached);
}
return cached;
}
return processClassName(name, GEMFIRE, GEODE, oldClassNamesToNew);
}
@Override
public String processIncomingClassName(String name, DataInput in) {
return processIncomingClassName(name);
}
@Override
public String processOutgoingClassName(String name, DataOutput out) {
// tcpserver was moved to a different package
String oldPackage = "com.gemstone.org.jgroups.stack.tcpserver";
String newPackage = "org.apache.geode.distributed.internal.tcpserver";
if (name.startsWith(newPackage)) {
return oldPackage + name.substring(newPackage.length());
}
if (ALWAYS_CONVERT_CLASSES) {
return processClassName(name, GEODE, GEMFIRE, newClassNamesToOld);
}
// if the client is old then it needs com.gemstone.gemfire package names
if (out instanceof VersionedDataOutputStream) {
VersionedDataOutputStream vout = (VersionedDataOutputStream) out;
Version version = vout.getVersion();
if (version != null && version.compareTo(Version.GFE_90) < 0) {
return processClassName(name, GEODE, GEMFIRE, newClassNamesToOld);
}
}
return name;
}
@Override
public Throwable getThrowable(Throwable theThrowable, Version clientVersion) {
if (theThrowable == null) {
return theThrowable;
}
if (clientVersion.compareTo(Version.GFE_90) >= 0) {
return theThrowable;
}
String className = theThrowable.getClass().getName();
// this class has been renamed, so it cannot be automatically translated
// during java deserialization
if (className.equals("org.apache.geode.cache.execute.EmptyRegionFunctionException")) {
return new EmtpyRegionFunctionException(theThrowable.getMessage(), theThrowable.getCause());
}
// other exceptions will be translated automatically by receivers
return theThrowable;
}
private String processClassName(String p_className, String oldPackage, String newPackage,
Map<String, String> cache) {
String cached = cache.get(p_className);
if (cached != null) {
return cached;
}
String className = p_className;
if (className.startsWith(oldPackage)) {
className = newPackage + className.substring(oldPackage.length());
} else if (className.startsWith("[") && className.contains("[L" + oldPackage)) {
int idx = className.indexOf("[L") + 2;
className =
className.substring(0, idx) + newPackage + className.substring(idx, oldPackage.length());
}
if (className != p_className) {
cache.put(p_className, className);
}
return className;
}
}