/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework 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 the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.common.protonetwork.model;
import static org.openbel.framework.common.BELUtilities.entries;
import static org.openbel.framework.common.BELUtilities.sizedHashMap;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.openbel.framework.common.InvalidArgument;
import org.openbel.framework.common.external.ExternalType;
import org.openbel.framework.common.external.ReadCache;
import org.openbel.framework.common.external.WriteCache;
import org.openbel.framework.common.protonetwork.model.NamespaceTable.TableNamespace;
import org.openbel.framework.common.protonetwork.model.StatementTable.TableStatement;
/**
* ParameterTable holds the parameter values for terms. This class manages the
* insertion index and occurrence count state through the
* {@link #addTableParameter(TableParameter)} operation.
*
* @author Anthony Bargnesi {@code <abargnesi@selventa.com>}
* @version 1.3 Derives from {@link ExternalType}
*/
public class ParameterTable extends ExternalType {
private static final long serialVersionUID = -6486699009265767006L;
private Set<TableParameter> parameters =
new LinkedHashSet<TableParameter>();
private Map<TableParameter, Integer> parameterIndex =
new HashMap<TableParameter, Integer>();
/**
* Defines a map of parameter index to global index. Note: This map is
* backed by {@link HashMap} which is not thread-safe.
*/
private Map<Integer, Integer> globalIndex = new HashMap<Integer, Integer>();
private Map<Integer, TableParameter> indexParameter =
new HashMap<Integer, TableParameter>();
private Map<TableParameter, Integer> count =
new HashMap<TableParameter, Integer>();
/**
* Defines a map of global index to {@link SkinnyUUID}
*/
private Map<Integer, SkinnyUUID> globalUUIDs =
new HashMap<Integer, SkinnyUUID>();
public int addTableParameter(TableParameter parameter) {
if (parameter == null) {
throw new InvalidArgument("parameter is null");
}
if (parameters.add(parameter)) {
int nextIndex = parameterIndex.size();
parameterIndex.put(parameter, nextIndex);
indexParameter.put(nextIndex, parameter);
globalIndex.put(nextIndex, globalIndex.size());
count.put(parameter, 1);
} else {
count.put(parameter, count.get(parameter) + 1);
}
return parameterIndex.get(parameter);
}
/**
* Removes a parameter by index, from the table's internal set and backing
* maps and adjusts indices.
* <p>
* If no parameter exists for the specified index, this method is a no-op.
* </p>
*
* @param pid Table parameter index
*/
public void removeTableParameter(final int pid) {
final TableParameter p = indexParameter.get(pid);
if (p == null) return;
// Pull the reference count
final Integer pcount = count.get(p);
// Alter maps and set only if 1 ref
if (pcount == 1 && parameters.remove(p)) {
Integer value = parameterIndex.remove(p);
indexParameter.remove(value);
count.remove(p);
} else {
count.put(p, pcount - 1);
}
}
/**
* Returns the table parameter by index.
*
* @param pid Table parameter index
* @return TableParameter
*/
public TableParameter getTableParameter(final int pid) {
return indexParameter.get(pid);
}
/**
* Returns an unmodifiable set view of the table parameters.
*
* @return Read-only {@link Set set}
*/
public Set<TableParameter> getTableParameters() {
return Collections.unmodifiableSet(parameters);
}
/**
* Returns {@link #getTableParameters()} as an array.
*
* @return {@code TableParameter[]}
*/
public TableParameter[] getTableParameterArray() {
return parameters.toArray(new TableParameter[0]);
}
/**
* @return Map with K: TableParameter; V: index
*/
public Map<TableParameter, Integer> getTableParameterIndex() {
return Collections.unmodifiableMap(parameterIndex);
}
/**
* @return Map with K: index; V: TableParameter
*/
public Map<Integer, TableParameter> getIndexTableParameter() {
return Collections.unmodifiableMap(indexParameter);
}
public Map<TableParameter, Integer> getCount() {
return Collections.unmodifiableMap(count);
}
/**
* @return Map with K: parameter index; V: global index
*/
public Map<Integer, Integer> getGlobalIndex() {
return globalIndex;
}
/**
* @return Map with K: parameter index; V: {@link SkinnyUUID} UUID
*/
public Map<Integer, SkinnyUUID> getGlobalUUIDs() {
return globalUUIDs;
}
/**
* @return all UUIDs present in the parameter table
*/
public Set<SkinnyUUID> getUUIDs() {
return Collections.unmodifiableSet(
new LinkedHashSet<SkinnyUUID>(globalUUIDs.values()));
}
/**
* {@inheritDoc}
*/
@Override
protected void _from(ObjectInput in) throws IOException,
ClassNotFoundException {
// 1: read parameter size
final int size = in.readInt();
// size collections accordingly
parameters = new LinkedHashSet<TableParameter>(size);
indexParameter = sizedHashMap(size);
parameterIndex = sizedHashMap(size);
count = sizedHashMap(size);
for (int i = 0; i < size; i++) {
TableParameter tp = new TableParameter();
// 1: read each table parameter
tp.readExternal(in);
parameters.add(tp);
// 2: read index
Integer idx = readInteger(in);
indexParameter.put(idx, tp);
parameterIndex.put(tp, idx);
// 3: read table parameter count
Integer pct = readInteger(in);
count.put(tp, pct);
}
// 2: read number of global indices
final int size2 = in.readInt();
// size map accordingly
globalIndex = sizedHashMap(size2);
for (int i = 0; i < size2; i++) {
// read each key/value
Integer key = readInteger(in);
Integer value = readInteger(in);
globalIndex.put(key, value);
}
// 3: read number of uuids
final int size3 = in.readInt();
globalUUIDs = sizedHashMap(size3);
for (int i = 0; i < size3; i++) {
Integer key = readInteger(in);
Long msb = readLong(in);
Long lsb = readLong(in);
globalUUIDs.put(key, new SkinnyUUID(msb, lsb));
}
}
/**
* {@inheritDoc}
*/
@Override
protected void _to(ObjectOutput out) throws IOException {
// 1: write parameters and indices
out.writeInt(parameters.size());
for (TableParameter tp : parameters) {
// 1: write each table parameter
tp.writeExternal(out);
// 2: write index
writeInteger(out, parameterIndex.get(tp));
// 3: write table parameter count
writeInteger(out, count.get(tp));
}
// 2: write number of global indices
out.writeInt(globalIndex.size());
for (final Entry<Integer, Integer> e : entries(globalIndex)) {
// write each key/value
writeInteger(out, e.getKey());
writeInteger(out, e.getValue());
}
// 3: write number of uuids
out.writeInt(globalUUIDs.size());
for (final Entry<Integer, SkinnyUUID> e : entries(globalUUIDs)) {
writeInteger(out, e.getKey());
writeLong(out, e.getValue().getMostSignificantBits());
writeLong(out, e.getValue().getLeastSignificantBits());
}
}
/**
* {@inheritDoc}
*/
@Override
protected void _from(ObjectInput in, ReadCache cache)
throws IOException,
ClassNotFoundException {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
@Override
protected void _to(ObjectOutput out, WriteCache cache)
throws IOException {
throw new UnsupportedOperationException();
}
/**
* @version 1.3 Derives from {@link ExternalType}
*/
public static class TableParameter extends ExternalType {
private static final long serialVersionUID = -6486699009265767005L;
private/* final */TableNamespace namespace;
private/* final */String value;
private/* final */int hash;
public TableParameter(String value) {
if (value == null) {
throw new InvalidArgument("value is null.");
}
this.namespace = null;
this.value = value;
this.hash = computeHash();
}
public TableParameter(TableNamespace namespace, String value) {
if (namespace == null) {
throw new InvalidArgument("namespace is null.");
}
if (value == null) {
throw new InvalidArgument("value is null.");
}
this.namespace = namespace;
this.value = value;
this.hash = computeHash();
}
/*
* This public, no-argument constructor is required when implementing Externalizable
* but it is not meant to be used for anything else.
*/
public TableParameter() {
}
public TableNamespace getNamespace() {
return namespace;
}
public String getValue() {
return value;
}
/**
* Compute the hashCode of {@link TableStatement this table statement}.
*
* @return the hashCode
*/
private int computeHash() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((namespace == null) ? 0 : namespace.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return hash;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TableParameter other = (TableParameter) obj;
if (namespace == null) {
if (other.namespace != null)
return false;
} else if (!namespace.equals(other.namespace))
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
/**
* {@inheritDoc}
*/
@Override
protected void _from(ObjectInput in) throws IOException,
ClassNotFoundException {
readNamespace(in);
value = readString(in);
hash = computeHash();
}
void readNamespace(ObjectInput in) throws IOException,
ClassNotFoundException {
byte nsnull = in.readByte();
if (nsnull == 1) {
namespace = new TableNamespace();
namespace.readExternal(in);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void _to(ObjectOutput out) throws IOException {
writeNamespace(out);
out.writeObject(value);
}
void writeNamespace(ObjectOutput out) throws IOException {
if (namespace == null) {
out.writeByte(0);
} else {
out.writeByte(1);
namespace.writeExternal(out);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void _from(ObjectInput in, ReadCache cache)
throws IOException,
ClassNotFoundException {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
@Override
protected void _to(ObjectOutput out, WriteCache cache)
throws IOException {
throw new UnsupportedOperationException();
}
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((count == null) ? 0 : count.hashCode());
result =
prime * result
+ ((globalIndex == null) ? 0 : globalIndex.hashCode());
result =
prime
* result
+ ((indexParameter == null) ? 0 : indexParameter
.hashCode());
result =
prime
* result
+ ((parameterIndex == null) ? 0 : parameterIndex
.hashCode());
result =
prime * result
+ ((parameters == null) ? 0 : parameters.hashCode());
return result;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ParameterTable other = (ParameterTable) obj;
if (count == null) {
if (other.count != null)
return false;
} else if (!count.equals(other.count))
return false;
if (globalIndex == null) {
if (other.globalIndex != null)
return false;
} else if (!globalIndex.equals(other.globalIndex))
return false;
if (indexParameter == null) {
if (other.indexParameter != null)
return false;
} else if (!indexParameter.equals(other.indexParameter))
return false;
if (parameterIndex == null) {
if (other.parameterIndex != null)
return false;
} else if (!parameterIndex.equals(other.parameterIndex))
return false;
if (parameters == null) {
if (other.parameters != null)
return false;
} else if (!parameters.equals(other.parameters))
return false;
return true;
}
}