| /* |
| * 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; |
| } |
| |
| |
| } |