/* * 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 org.apache.geode.pdx.internal; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.geode.InternalGemFireError; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.client.Pool; import org.apache.geode.cache.client.ServerConnectivityException; import org.apache.geode.cache.client.internal.AddPDXEnumOp; import org.apache.geode.cache.client.internal.AddPDXTypeOp; import org.apache.geode.cache.client.internal.ExecutablePool; import org.apache.geode.cache.client.internal.GetPDXEnumByIdOp; import org.apache.geode.cache.client.internal.GetPDXEnumsOp; import org.apache.geode.cache.client.internal.GetPDXIdForEnumOp; import org.apache.geode.cache.client.internal.GetPDXIdForTypeOp; import org.apache.geode.cache.client.internal.GetPDXTypeByIdOp; import org.apache.geode.cache.client.internal.GetPDXTypesOp; import org.apache.geode.cache.client.internal.PoolImpl; import org.apache.geode.cache.wan.GatewaySender; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.PoolManagerImpl; import org.apache.geode.internal.logging.LogService; public class ClientTypeRegistration implements TypeRegistration { private static final Logger logger = LogService.getLogger(); private final GemFireCacheImpl cache; public ClientTypeRegistration(GemFireCacheImpl cache) { this.cache = cache; } public int defineType(PdxType newType) { Collection<Pool> pools = getAllPools(); ServerConnectivityException lastException = null; int newTypeId = -1; for (Pool pool : pools) { try { newTypeId = GetPDXIdForTypeOp.execute((ExecutablePool) pool, newType); newType.setTypeId(newTypeId); sendTypeToPool(newType, newTypeId, pool); return newTypeId; } catch (ServerConnectivityException e) { // ignore, try the next pool. lastException = e; } } throw returnCorrectExceptionForFailure(pools, newTypeId, lastException); } private void sendTypeToPool(PdxType type, int id, Pool pool) { try { AddPDXTypeOp.execute((ExecutablePool) pool, id, type); } catch (ServerConnectivityException serverConnectivityException) { logger.debug("Received an exception sending pdx type to pool {}, {}", pool, serverConnectivityException.getMessage(), serverConnectivityException); throw serverConnectivityException; } } public PdxType getType(int typeId) { Collection<Pool> pools = getAllPools(); ServerConnectivityException lastException = null; for (Pool pool : pools) { try { PdxType type = GetPDXTypeByIdOp.execute((ExecutablePool) pool, typeId); if (type != null) { return type; } } catch (ServerConnectivityException e) { logger.debug("Received an exception getting pdx type from pool {}, {}", pool, e.getMessage(), e); // ignore, try the next pool. lastException = e; } } if (lastException != null) { throw lastException; } else { throw returnCorrectExceptionForFailure(pools, typeId, lastException); } } private Collection<Pool> getAllPools() { Collection<Pool> pools = PoolManagerImpl.getPMI().getMap().values(); for (Iterator<Pool> itr = pools.iterator(); itr.hasNext();) { PoolImpl pool = (PoolImpl) itr.next(); if (pool.isUsedByGateway()) { itr.remove(); } } if (pools.isEmpty()) { if (this.cache.isClosed()) { throw new CacheClosedException("PDX detected cache was closed"); } throw new CacheClosedException( "Client pools have been closed so the PDX type registry is not available."); } return pools; } public void addRemoteType(int typeId, PdxType type) { throw new UnsupportedOperationException("Clients will not be asked to add remote types"); } public int getLastAllocatedTypeId() { throw new UnsupportedOperationException("Clients does not keep track of last allocated id"); } public void initialize() { // do nothing } public void gatewaySenderStarted(GatewaySender gatewaySender) { // do nothing } public void creatingPersistentRegion() { // do nothing } public void creatingPool() { // do nothing } public int getEnumId(Enum<?> v) { EnumInfo enumInfo = new EnumInfo(v); return processEnumInfoForEnumId(enumInfo); } private int processEnumInfoForEnumId(EnumInfo enumInfo) { Collection<Pool> pools = getAllPools(); ServerConnectivityException lastException = null; for (Pool pool : pools) { try { int result = GetPDXIdForEnumOp.execute((ExecutablePool) pool, enumInfo); sendEnumIdToPool(enumInfo, result, pool); return result; } catch (ServerConnectivityException e) { // ignore, try the next pool. lastException = e; } } throw returnCorrectExceptionForFailure(pools, -1, lastException); } private void sendEnumIdToPool(EnumInfo enumInfo, int id, Pool pool) { try { AddPDXEnumOp.execute((ExecutablePool) pool, id, enumInfo); } catch (ServerConnectivityException serverConnectivityException) { logger.debug("Received an exception sending pdx type to pool {}, {}", pool, serverConnectivityException.getMessage(), serverConnectivityException); throw serverConnectivityException; } } public void addRemoteEnum(int enumId, EnumInfo newInfo) { throw new UnsupportedOperationException("Clients will not be asked to add remote enums"); } public int defineEnum(EnumInfo newInfo) { return processEnumInfoForEnumId(newInfo); } public EnumInfo getEnumById(int enumId) { Collection<Pool> pools = getAllPools(); ServerConnectivityException lastException = null; for (Pool pool : pools) { try { EnumInfo result = GetPDXEnumByIdOp.execute((ExecutablePool) pool, enumId); if (result != null) { return result; } } catch (ServerConnectivityException e) { logger.debug("Received an exception getting pdx type from pool {}, {}", pool, e.getMessage(), e); // ignore, try the next pool. lastException = e; } } throw returnCorrectExceptionForFailure(pools, enumId, lastException); } @SuppressWarnings({"unchecked", "serial"}) @Override public Map<Integer, PdxType> types() { Collection<Pool> pools = getAllPools(); Map<Integer, PdxType> types = new HashMap<>(); for (Pool p : pools) { try { types.putAll(GetPDXTypesOp.execute((ExecutablePool) p)); } catch (Exception e) { e.printStackTrace(); } } return types; } @SuppressWarnings({"unchecked", "serial"}) @Override public Map<Integer, EnumInfo> enums() { Collection<Pool> pools = getAllPools(); Map<Integer, EnumInfo> enums = new HashMap<>(); for (Pool p : pools) { enums.putAll(GetPDXEnumsOp.execute((ExecutablePool) p)); } return enums; } @Override public PdxType getPdxTypeForField(String fieldName, String className) { for (Object value : types().values()) { if (value instanceof PdxType) { PdxType pdxType = (PdxType) value; if (pdxType.getClassName().equals(className) && pdxType.getPdxField(fieldName) != null) { return pdxType; } } } return null; } @Override public void testClearRegistry() {} @Override public boolean isClient() { return true; } @Override public void addImportedType(int typeId, PdxType importedType) { Collection<Pool> pools = getAllPools(); ServerConnectivityException lastException = null; for (Pool pool : pools) { try { sendTypeToPool(importedType, typeId, pool); } catch (ServerConnectivityException e) { lastException = e; break; } } if (lastException == null) { return; } throw returnCorrectExceptionForFailure(pools, typeId, lastException); } @Override public void addImportedEnum(int enumId, EnumInfo importedInfo) { Collection<Pool> pools = getAllPools(); ServerConnectivityException lastException = null; for (Pool pool : pools) { try { sendEnumIdToPool(importedInfo, enumId, pool); } catch (ServerConnectivityException e) { lastException = e; break; } } if (lastException == null) { return; } throw returnCorrectExceptionForFailure(pools, enumId, lastException); } private RuntimeException returnCorrectExceptionForFailure(final Collection<Pool> pools, final int typeId, final ServerConnectivityException lastException) { if (lastException != null) { throw lastException; } else { throw new InternalGemFireError("Unable to determine PDXType for id " + typeId); } } @Override public int getLocalSize() { return 0; } }