/* * Copyright Terracotta, Inc. * * Licensed 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.ehcache.core.config; import org.ehcache.config.ResourcePool; import org.ehcache.config.ResourcePools; import org.ehcache.config.ResourceType; import org.ehcache.config.SizedResourcePool; import org.ehcache.core.HumanReadable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * Implementation of the {@link ResourcePools} interface. */ public class ResourcePoolsImpl implements ResourcePools, HumanReadable { private final Map<ResourceType<?>, ResourcePool> pools; public ResourcePoolsImpl(Map<ResourceType<?>, ResourcePool> pools) { if (pools.isEmpty()) { throw new IllegalArgumentException("No resource pools defined"); } validateResourcePools(pools.values()); this.pools = pools; } /** * {@inheritDoc} */ @Override public <P extends ResourcePool> P getPoolForResource(ResourceType<P> resourceType) { return resourceType.getResourcePoolClass().cast(pools.get(resourceType)); } /** * {@inheritDoc} */ @Override public Set<ResourceType<?>> getResourceTypeSet() { return pools.keySet(); } /** * {@inheritDoc} */ @Override public ResourcePools validateAndMerge(ResourcePools toBeUpdated) { // Ensure update pool types already exist in existing pools if(!getResourceTypeSet().containsAll(toBeUpdated.getResourceTypeSet())) { throw new IllegalArgumentException("Pools to be updated cannot contain previously undefined resources pools"); } // Can not update OFFHEAP if(toBeUpdated.getResourceTypeSet().contains(ResourceType.Core.OFFHEAP)) { throw new UnsupportedOperationException("Updating OFFHEAP resource is not supported"); } // Can not update DISK if(toBeUpdated.getResourceTypeSet().contains(ResourceType.Core.DISK)) { throw new UnsupportedOperationException("Updating DISK resource is not supported"); } for(ResourceType<?> currentResourceType : toBeUpdated.getResourceTypeSet()) { getPoolForResource(currentResourceType).validateUpdate(toBeUpdated.getPoolForResource(currentResourceType)); } Map<ResourceType<?>, ResourcePool> poolsMap = new HashMap<ResourceType<?>, ResourcePool>(); poolsMap.putAll(pools); for(ResourceType<?> currentResourceType : toBeUpdated.getResourceTypeSet()) { ResourcePool poolForResource = toBeUpdated.getPoolForResource(currentResourceType); poolsMap.put(currentResourceType, poolForResource); } return new ResourcePoolsImpl(poolsMap); } /** * Validates some required relationships between {@link org.ehcache.config.ResourceType.Core core resources}. * * @param pools the resource pools to validate */ public static void validateResourcePools(Collection<? extends ResourcePool> pools) { List<SizedResourcePool> ordered = new ArrayList<SizedResourcePool>(pools.size()); for(ResourcePool pool : pools) { if (pool instanceof SizedResourcePool) { ordered.add((SizedResourcePool)pool); } } Collections.sort(ordered, new Comparator<SizedResourcePool>() { @Override public int compare(final SizedResourcePool o1, final SizedResourcePool o2) { int retVal = o2.getType().getTierHeight() - o1.getType().getTierHeight(); if(retVal == 0) { return o1.toString().compareTo(o2.toString()); } else { return retVal; } } }); for (int i = 0; i < ordered.size(); i++) { for (int j = 0; j < i; j++) { SizedResourcePool upper = ordered.get(j); SizedResourcePool lower = ordered.get(i); boolean inversion; boolean ambiguity; try { ambiguity = upper.getType().getTierHeight() == lower.getType().getTierHeight(); inversion = (upper.getUnit().compareTo(upper.getSize(), lower.getSize(), lower.getUnit()) >= 0) || (lower.getUnit().compareTo(lower.getSize(), upper.getSize(), upper.getUnit()) <= 0); } catch (IllegalArgumentException e) { ambiguity = false; inversion = false; } if (ambiguity) { throw new IllegalArgumentException("Tiering Ambiguity: '" + upper + "' has the same tier height as '" + lower + "'"); } if (inversion) { throw new IllegalArgumentException("Tiering Inversion: '" + upper + "' is not smaller than '" + lower + "'"); } } } } @Override public String readableString() { Map<ResourceType<?>, ResourcePool> sortedPools = new TreeMap<ResourceType<?>, ResourcePool>( new Comparator<ResourceType<?>>() { @Override public int compare(ResourceType<?> o1, ResourceType<?> o2) { return o2.getTierHeight() - o1.getTierHeight(); } } ); sortedPools.putAll(pools); StringBuilder poolsToStringBuilder = new StringBuilder(); for (Map.Entry<ResourceType<?>, ResourcePool> poolEntry : sortedPools.entrySet()) { poolsToStringBuilder .append(poolEntry.getKey()) .append(": ") .append("\n ") .append("size: ") .append(poolEntry.getValue() instanceof HumanReadable ? ((HumanReadable) poolEntry.getValue()).readableString() : poolEntry.getValue()) .append("\n ") .append("tierHeight: ") .append(poolEntry.getKey().getTierHeight()) .append("\n "); } if (poolsToStringBuilder.length() > 4) { poolsToStringBuilder.delete(poolsToStringBuilder.length() - 5, poolsToStringBuilder.length()); } return "pools: " + "\n " + poolsToStringBuilder.toString(); } }