/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.metadata;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicLong;
import org.teiid.core.util.StringUtil;
import org.teiid.designer.runtime.version.spi.TeiidServerVersion.Version;
/**
* AbstractMetadataRecord
*/
public abstract class AbstractMetadataRecord implements Serializable {
private static final Collection<AbstractMetadataRecord> EMPTY_INCOMING = Collections.emptyList();
public interface Modifiable {
long getLastModified();
}
public interface DataModifiable {
String DATA_TTL = AbstractMetadataRecord.RELATIONAL_URI + "data-ttl"; //$NON-NLS-1$
long getLastDataModification();
}
private static final long serialVersionUID = 564092984812414058L;
public final static char NAME_DELIM_CHAR = '.';
private static AtomicLong UUID_SEQUENCE = new AtomicLong();
private String uuid; //globally unique id
private String name; //contextually unique name
private String nameInSource;
private volatile Map<String, String> properties;
private String annotation;
private transient Collection<AbstractMetadataRecord> incomingObjects;
public static final String RELATIONAL_URI = "{http://www.teiid.org/ext/relational/2012}"; //$NON-NLS-1$
public String getUUID() {
if (uuid == null) {
uuid = String.valueOf(UUID_SEQUENCE.getAndIncrement());
}
return uuid;
}
public void setUUID(String uuid) {
this.uuid = uuid;
}
public String getNameInSource() {
return nameInSource;
}
public void setNameInSource(String nameInSource) {
this.nameInSource = nameInSource;
}
/**
* Get the name in source or the name if
* the name in source is not set.
* @return
*/
public String getSourceName() {
if (this.nameInSource != null && this.nameInSource.length() > 0) {
return this.nameInSource;
}
return getName();
}
/**
* WARNING - The name returned by this method may be ambiguous and
* is not SQL safe - it may need quoted/escaped
*/
public String getFullName() {
AbstractMetadataRecord parent = getParent();
if (parent != null) {
String result = parent.getFullName() + NAME_DELIM_CHAR + getName();
return result;
}
return name;
}
public void getSQLString(StringBuilder sb) {
AbstractMetadataRecord parent = getParent();
if (parent != null) {
parent.getSQLString(sb);
sb.append(NAME_DELIM_CHAR);
}
sb.append('"').append(StringUtil.replace(name, "\"", "\"\"")).append('"'); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Get the full name as a SQL safe string
* @return
*/
public String getSQLString() {
StringBuilder sb = new StringBuilder();
getSQLString(sb);
return sb.toString();
}
public AbstractMetadataRecord getParent() {
return null;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCanonicalName() {
return name.toUpperCase();
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer(100);
sb.append(getClass().getSimpleName());
sb.append(" name="); //$NON-NLS-1$
sb.append(getName());
sb.append(", nameInSource="); //$NON-NLS-1$
sb.append(getNameInSource());
sb.append(", uuid="); //$NON-NLS-1$
sb.append(getUUID());
return sb.toString();
}
/**
* Return the extension properties for this record - may be unmodifiable
* if {@link #setProperties(LinkedHashMap)} or {@link #setProperty(String, String)}
* has not been called.
* @return
*/
public Map<String, String> getProperties() {
if (properties == null) {
return Collections.emptyMap();
}
return properties;
}
public String getProperty(String key, boolean checkUnqualified) {
String value = getProperties().get(key);
if (value != null || !checkUnqualified) {
return value;
}
int index = key.indexOf('}');
if (index > 0 && index < key.length() && key.charAt(0) == '{') {
key = key.substring(index + 1, key.length());
}
return getProperties().get(key);
}
/**
* The preferred setter for extension properties.
* @param key
* @param value, if null the property will be removed
*/
public String setProperty(String key, String value) {
if (this.properties == null) {
synchronized (this) {
if (this.properties == null && value == null) {
return null;
}
this.properties = new ConcurrentSkipListMap<String, String>(String.CASE_INSENSITIVE_ORDER);
}
}
if (value == null) {
return this.properties.remove(key);
}
return this.properties.put(key, value);
}
public synchronized void setProperties(Map<String, String> properties) {
if (this.properties == null) {
this.properties = new ConcurrentSkipListMap<String, String>(String.CASE_INSENSITIVE_ORDER);
} else {
this.properties.clear();
}
if (properties != null) {
this.properties.putAll(properties);
}
}
public String getAnnotation() {
return annotation;
}
public void setAnnotation(String annotation) {
this.annotation = annotation;
}
/**
* Compare two records for equality.
*/
@Override
public boolean equals(Object obj) {
if(obj == this) {
return true;
}
if(obj.getClass() != this.getClass()) {
return false;
}
AbstractMetadataRecord other = (AbstractMetadataRecord)obj;
if (getUUID() == other.getUUID()) {
return true;
} else if (getUUID() == null || other.getUUID() == null) {
return false;
} else {
return getUUID().equals(other.getUUID());
}
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
if (this.properties != null && !(this.properties instanceof ConcurrentSkipListMap<?, ?>)) {
this.properties = new ConcurrentSkipListMap<String, String>(this.properties);
}
}
@Override
public int hashCode() {
return getUUID().hashCode();
}
public Collection<AbstractMetadataRecord> getIncomingObjects() {
if (incomingObjects == null) {
return EMPTY_INCOMING;
}
return incomingObjects;
}
public void setIncomingObjects(Collection<AbstractMetadataRecord> incomingObjects) {
this.incomingObjects = incomingObjects;
}
public boolean isUUIDSet() {
return this.uuid != null && this.uuid.length() > 0 && !Character.isDigit(this.uuid.charAt(0));
}
}