/* * 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.meta; import java.io.File; import java.io.Serializable; import java.security.AccessController; import java.security.PrivilegedActionException; import org.apache.openjpa.lib.util.StringUtil; import org.apache.openjpa.conf.SeqValue; import org.apache.openjpa.kernel.Seq; import org.apache.openjpa.lib.conf.Configurations; import org.apache.openjpa.lib.conf.PluginValue; import org.apache.openjpa.lib.meta.SourceTracker; import org.apache.openjpa.lib.util.Closeable; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.xml.Commentable; import org.apache.openjpa.util.MetaDataException; import org.apache.openjpa.util.OpenJPAException; /** * Metadata about a named sequence. * * @author Abe White * @since 0.4.0 */ public class SequenceMetaData implements SourceTracker, MetaDataContext, Closeable, Commentable, Serializable { /** * Sequence name that means to use the system default sequence. */ public static final String NAME_SYSTEM = "system"; /** * Default plugin alias name; every back end should have some 'native' * sequence implementation. */ public static final String IMPL_NATIVE = "native"; /** * Time-based sequence values. */ public static final String IMPL_TIME = "time"; // plugin property names for standard props private static final String PROP_SEQUENCE = "Sequence"; private static final String PROP_INITIAL_VALUE = "InitialValue"; private static final String PROP_ALLOCATE = "Allocate"; private static final String PROP_INCREMENT = "Increment"; private static final String PROP_SCHEMA = "Schema"; private static final String PROP_CATALOG = "Catalog"; private static final Localizer _loc = Localizer.forPackage (SequenceMetaData.class); private MetaDataRepository _repos; private SequenceFactory _factory = null; private final String _name; private int _type = Seq.TYPE_DEFAULT; private String _plugin = IMPL_NATIVE; private File _source = null; private Object _scope = null; private int _srcType = SRC_OTHER; private int _lineNum = 0; private int _colNum = 0; private String[] _comments = null; private String _sequence = null; private int _increment = -1; private int _allocate = -1; private int _initial = -1; private String _schema = null; private String _catalog = null; // instantiated lazily private transient Seq _instance = null; /** * Constructor; supply sequence name. */ public SequenceMetaData(String name, MetaDataRepository repos) { _name = name; _repos = repos; } /** * The owning repository. */ public MetaDataRepository getRepository() { return _repos; } /** * The sequence name. */ public String getName() { return _name; } public File getSourceFile() { return _source; } public Object getSourceScope() { return _scope; } public int getSourceType() { return _srcType; } public void setSource(File file, Object scope, int srcType) { _source = file; _scope = scope; _srcType = srcType; } public int getLineNumber() { return _lineNum; } public void setLineNumber(int lineNum) { _lineNum = lineNum; } public int getColNumber() { return _colNum; } public void setColNumber(int colNum) { _colNum = colNum; } public String getResourceName() { return _name; } /** * The sequence type. */ public int getType() { return _type; } /** * The sequence type. */ public void setType(int type) { _type = type; } /** * Native sequence name. */ public String getSequence() { return _sequence; } /** * Native sequence name. */ public void setSequence(String sequence) { _sequence = sequence; } /** * Sequence increment, or -1 for default. */ public int getIncrement() { return _increment; } /** * Sequence increment, or -1 for default. */ public void setIncrement(int increment) { _increment = increment; } /** * Sequence values to allocate, or -1 for default. */ public int getAllocate() { return _allocate; } /** * Sequence values to allocate, or -1 for default. */ public void setAllocate(int allocate) { _allocate = allocate; } /** * Initial sequence value, or -1 for default. */ public int getInitialValue() { return _initial; } /** * Initial sequence value, or -1 for default. */ public void setInitialValue(int initial) { _initial = initial; } /** * Plugin string describing the {@link Seq}. */ public String getSequencePlugin() { return _plugin; } /** * Plugin string describing the {@link Seq}. */ public void setSequencePlugin(String plugin) { _plugin = plugin; } /** * A factory to transform spec sequences produced by user factories into * the OpenJPA sequence type. */ public SequenceFactory getSequenceFactory() { return _factory; } /** * A factory to transform spec sequences produced by user factories into * the OpenJPA sequence type. */ public void setSequenceFactory(SequenceFactory factory) { _factory = factory; } /** * Return the initialized sequence instance. */ public synchronized Seq getInstance(ClassLoader envLoader) { if (_instance == null) _instance = instantiate(envLoader); return _instance; } /** * Create a new uninitialized instance of this sequence. */ protected Seq instantiate(ClassLoader envLoader) { if (NAME_SYSTEM.equals(_name)) return _repos.getConfiguration().getSequenceInstance(); try { PluginValue plugin = newPluginValue("sequence-plugin"); plugin.setString(_plugin); String clsName = plugin.getClassName(); Class cls = null; try { cls = Class.forName(clsName, true, AccessController.doPrivileged(J2DoPrivHelper.getClassLoaderAction(Seq.class))); } catch (ClassNotFoundException cnfe) { // Target sequence type is loaded by the ClassLoader responsible for OpenJPA classes. // This can happen if the custom sequence implementation is a class that belongs to // a child ClassLoader - a situation that can easily happen in a JEE environment. // Fall back to the envLoader to try load the class. cls = Class.forName(clsName, true, envLoader); } StringBuilder props = new StringBuilder(); if (plugin.getProperties() != null) props.append(plugin.getProperties()); addStandardProperties(props); // allow user-class specification of either our sequence // interface or a factory class Seq seq; if (Seq.class.isAssignableFrom(cls)) { seq = (Seq) AccessController.doPrivileged( J2DoPrivHelper.newInstanceAction(cls)); Configurations.configureInstance(seq, _repos.getConfiguration(), props.toString()); if(_type != Seq.TYPE_DEFAULT) seq.setType(_type); } else if (_factory != null) seq = _factory.toSequence(cls, props.toString()); else throw new MetaDataException(_loc.get("not-seq-cls", _name, cls)); return seq; } catch (OpenJPAException ke) { throw ke; } catch (Exception e) { if (e instanceof PrivilegedActionException) e = ((PrivilegedActionException) e).getException(); throw new MetaDataException(_loc.get("cant-init-seq", _name)). setCause(e); } } /* * Set/Get the schema name */ public void setSchema(String schema) { // If the schema name is empty, check to see if a system // level default exists and if so use it. if (schema == null || "".equals(schema)){ String tmp = getRepository().getMetaDataFactory().getDefaults().getDefaultSchema(); schema = (tmp != null ? tmp : ""); } this._schema = schema; } public String getSchema() { return _schema; } /* * Set/Get the catalog name */ public void setCatalog(String catalog) { this._catalog = catalog; } public String getCatalog() { return _catalog; } /** * Create a new plugin value for sequences. Returns a standard * {@link SeqValue} by default. */ protected PluginValue newPluginValue(String property) { return new SeqValue(property); } /** * Add standard properties to the given properties buffer. */ protected void addStandardProperties(StringBuilder props) { appendProperty(props, PROP_SEQUENCE, wrapValue(_sequence)); appendProperty(props, PROP_INITIAL_VALUE, _initial); appendProperty(props, PROP_ALLOCATE, _allocate); appendProperty(props, PROP_INCREMENT, _increment); appendProperty(props, PROP_SCHEMA, wrapValue(_schema)); appendProperty(props, PROP_CATALOG, wrapValue(_catalog)); } /** * Wraps property values that may contain spaces or other special characters * in double quotes so they are processed as a single valued argument. */ protected String wrapValue(String value) { if (value != null) { return "\"" + value + "\""; } return value; } /** * Add a string property to the buffer. Nothing will be added if value * is null or empty string. */ protected void appendProperty(StringBuilder props, String name, String val) { if (StringUtil.isEmpty(val)) return; if (props.length() > 0) props.append(","); props.append(name).append("=").append(val); } /** * Add an int property to the buffer. Nothing will be added if value is -1. */ protected void appendProperty(StringBuilder props, String name, int val) { if (val == -1) return; if (props.length() > 0) props.append(","); props.append(name).append("=").append(val); } /** * Close user sequence instance. */ public void close() { if (_instance != null && !NAME_SYSTEM.equals(_name)) try { _instance.close(); } catch (Exception e) { } } @Override public String toString() { return _name; } /////////////// // Commentable /////////////// public String[] getComments() { return (_comments == null) ? EMPTY_COMMENTS : _comments; } public void setComments(String[] comments) { _comments = comments; } /** * Allow facades to supply adapters from a spec sequence type to the * OpenJPA sequence type. */ public static interface SequenceFactory extends Serializable { /** * Transform the given class named in metadata into a sequence. */ public Seq toSequence (Class cls, String props) throws Exception; } }