Package org.apache.openjpa.datacache

Source Code of org.apache.openjpa.datacache.PartitionedDataCache

/*
* 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.openjpa.datacache;

import java.lang.reflect.Array;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.openjpa.lib.conf.PluginListValue;
import org.apache.openjpa.lib.conf.Value;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.util.UserException;

/**
* A partitioned data cache maintains a set of partitions that are DataCache themselves.
* Each of the partitioned DataCaches can be individually configured.
* However, all partitions must be of the same type. By default, this cache uses
* {@linkplain ConcurrentDataCache} as its partitions.
* <br>
* This cache can be configured as a plug-in as follows:
* <br>
* <code>&lt;property name='openjpa.DataCache"
*         value="partitioned(name=X, PartitionType=concurrent,Partitions='(name=a,cacheSize=100),
*         (name=b,cacheSize=200)')</code>
* <br>
* Notice that the individual partition properties are enclosed parentheses, separated by comma
* and finally the whole property string is enclosed in single quote.
* Each partition must have a non-empty name that are unique among the partitions.
* The {@linkplain CacheDistributionPolicy policy} can return
* the name of a partition to distribute the managed instances to be cached in respective partition.
* The above configuration will configure a partitioned cache named <code>X</code> with two partitions named
* <code>a</code> and <code>b</code> with cache size <code>100</code> and <code>200</code> respectively.
* Besides the two partitions, this cache instance itself can store data and referred by its own name
* (<code>X</code> in the above example).
* <br>
*
* @author Pinaki Poddar
*
* @since 2.0.0
*/
@SuppressWarnings("serial")
public class PartitionedDataCache extends ConcurrentDataCache {
    private static final Localizer _loc = Localizer.forPackage(PartitionedDataCache.class);
    private Class<? extends DataCache> _type = ConcurrentDataCache.class;
    private final List<String> _partProperties = new ArrayList<String>();
    private final Map<String, DataCache> _partitions = new HashMap<String, DataCache>();
   
    /**
     * Sets the type of the partitions.
     * Each partition is a DataCache itself.
     *
     * @param type the name of the type that implements {@linkplain DataCache} interface.
     * Aliases such as <code>"concurrent"</code> is also recognized.
     *
     * @throws Exception if the given type is not resolvable to a loadable type.
     */
    public void setPartitionType(String type) throws Exception {
        Value value = conf.getValue("DataCache");
        ClassLoader ctxLoader = AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
        ClassLoader loader = conf.getClassResolverInstance().getClassLoader(null, ctxLoader);
        _type = (Class<? extends DataCache>) AccessController.doPrivileged(
                J2DoPrivHelper.getForNameAction(value.unalias(type), true, loader));
    }
   
    /**
     * Set partitions from a String configuration.
     *
     * @param parts a String of the form <code>(p1, p2, p3)</code> where p1, p2 etc. itself are plug-in strings
     * for individual Data Cache configuration.
     */
    public void setPartitions(String parts) {
        _partProperties.clear();
        parsePartitionProperties(parts);
        PluginListValue partitions = new PluginListValue("partitions");
        String[] types = (String[])Array.newInstance(String.class, _partProperties.size());
        Arrays.fill(types, _type.getName());
        partitions.setClassNames(types);
        partitions.setProperties(_partProperties.toArray(new String[_partProperties.size()]));
        DataCache[] array = (DataCache[])partitions.instantiate(_type, conf);
        for (DataCache part : array) {
            if (part.getName() == null)
                throw new UserException(_loc.get("partition-cache-null-partition", parts));
            if (_partitions.containsKey(part.getName()))
                throw new UserException(_loc.get("partition-cache-duplicate-partition", part.getName(), parts));
            if (part.getName().equals(DataCache.NAME_DEFAULT))
                throw new UserException(_loc.get("partition-cache-default-partition", part.getName(), parts));
            _partitions.put(part.getName(), part);
        }
    }
   
    /**
     * Returns the individual partition configuration properties.
     */
    public List<String> getPartitions() {
        return _partProperties;
    }
   
    public DataCache getPartition(String name, boolean create) {
        return _partitions.get(name);
    }
   
    /**
     * Gets the name of the configured partitions.
     */
    public Set<String> getPartitionNames() {
        return _partitions.keySet();
    }
   
    /**
     * Always returns true.
     */
    public final boolean isPartitioned() {
        return !_partitions.isEmpty();
    }
   
    public void endConfiguration() {
        if (!isPartitioned())
            conf.getConfigurationLog().warn(_loc.get("partition-cache-no-config"));
    }
   
    /**
     * Parses property string of the form <code>(p1),(p2),(p3)</code> to produce a list of
     * <code>p1</code>, <code>p2</code> and <code>p3</code>. The component strings
     * <code>p1</code> etc. must be enclosed in parentheses and separated by comma.
     * plug-in string to produce a list of
     *
     * @param properties property string of the form <code>(p1),(p2),(p3)</code>
     */
    private void parsePartitionProperties(String full) {
        String properties = new String(full);
        while (true) {
            if (properties == null)
                break;
            properties = properties.trim();
            if (properties.length() == 0)
                break;
            if (properties.startsWith(",")) {
                properties = properties.substring(1);
            } else if (!_partProperties.isEmpty()) {
                throw new UserException(_loc.get("partition-cache-parse-error-comma", full, properties));
            }
            if (properties.startsWith("(") && properties.endsWith(")")) {
                int i = properties.indexOf(")");
                String p = properties.substring(1,i); // exclude the end parentheses
                _partProperties.add(p);
                 if (i < properties.length()-1) {
                    properties = properties.substring(i+1);
                 } else {
                     break;
                 }
            } else {
                throw new UserException(_loc.get("partition-cache-parse-error-paren", full, properties));
            }
        }
    }
}
TOP

Related Classes of org.apache.openjpa.datacache.PartitionedDataCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.