/*_############################################################################
_##
_## SNMP4J-AgentX - AgentXIndexRegistry.java
_##
_## Copyright (C) 2005-2009 Frank Fock (SNMP4J.org)
_##
_## This program is free software; you can redistribute it and/or modify
_## it under the terms of the GNU General Public License version 2 as
_## published by the Free Software Foundation.
_##
_## This program 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 General Public License for more details.
_##
_## You should have received a copy of the GNU General Public License
_## along with this program; if not, write to the Free Software
_## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
_## MA 02110-1301 USA
_##
_##########################################################################*/
package org.snmp4j.agent.agentx.master.index;
import java.util.*;
import org.snmp4j.agent.agentx.AgentXProtocol;
import org.snmp4j.smi.*;
import org.snmp4j.agent.agentx.master.index.AgentXIndexRegistry.IndexEntry;
import org.snmp4j.agent.agentx.master.index.AgentXIndexRegistry.IndexRegistryEntry;
import org.snmp4j.log.LogAdapter;
import org.snmp4j.log.LogFactory;
public class AgentXIndexRegistry {
private static final LogAdapter LOGGER =
LogFactory.getLogger(AgentXIndexRegistry.class);
private Map indexes = Collections.synchronizedMap(new HashMap());
public AgentXIndexRegistry() {
}
public int allocate(int sessionID,
OctetString context, VariableBinding vb,
boolean testOnly) {
try {
vb.getVariable().toSubIndex(true);
}
catch (UnsupportedOperationException ex) {
return AgentXProtocol.AGENTX_INDEX_WRONG_TYPE;
}
IndexRegistryEntry newEntry = new IndexRegistryEntry(context, vb);
IndexRegistryEntry oldEntry = (IndexRegistryEntry) indexes.get(newEntry);
if (oldEntry == null) {
if (!testOnly) {
int status = newEntry.allocate(sessionID, vb.getVariable(), testOnly);
if (status == AgentXProtocol.AGENTX_SUCCESS) {
indexes.put(newEntry, newEntry);
}
return status;
}
return AgentXProtocol.AGENTX_SUCCESS;
}
else {
return oldEntry.allocate(sessionID, vb.getVariable(), testOnly);
}
}
public int release(int sessionID,
OctetString context, VariableBinding vb,
boolean testOnly) {
IndexRegistryEntry newEntry = new IndexRegistryEntry(context, vb);
IndexRegistryEntry entry = (IndexRegistryEntry) indexes.get(newEntry);
if (entry == null) {
return AgentXProtocol.AGENTX_INDEX_NOT_ALLOCATED;
}
else {
if (entry.getIndexType().getSyntax() != vb.getSyntax()) {
return AgentXProtocol.AGENTX_INDEX_NOT_ALLOCATED;
}
return entry.release(sessionID, vb.getVariable(), testOnly);
}
}
public void release(int sessionID) {
synchronized (indexes) {
for (Iterator it = indexes.values().iterator(); it.hasNext(); ) {
IndexRegistryEntry entry = (IndexRegistryEntry) it.next();
entry.release(sessionID);
}
}
}
public int newIndex(int sessionID,
OctetString context, VariableBinding vb,
boolean testOnly) {
IndexRegistryEntry newEntry = new IndexRegistryEntry(context, vb);
IndexRegistryEntry entry = (IndexRegistryEntry) indexes.get(newEntry);
if (entry == null) {
entry = new IndexRegistryEntry(context, vb);
}
Variable v = entry.newIndex(sessionID, testOnly);
if (v == null) {
return AgentXProtocol.AGENTX_INDEX_NONE_AVAILABLE;
}
else if (!testOnly) {
vb.setVariable(v);
}
return AgentXProtocol.AGENTX_SUCCESS;
}
public int anyIndex(int sessionID,
OctetString context, VariableBinding vb,
boolean testOnly) {
IndexRegistryEntry newEntry = new IndexRegistryEntry(context, vb);
IndexRegistryEntry entry = (IndexRegistryEntry) indexes.get(newEntry);
boolean newEntryCreated = false;
if (entry == null) {
entry = new IndexRegistryEntry(context, vb);
newEntryCreated = true;
}
Variable v = entry.anyIndex(sessionID, testOnly);
if (v == null) {
return AgentXProtocol.AGENTX_INDEX_NONE_AVAILABLE;
}
else if (!testOnly) {
vb.setVariable(v);
if (newEntryCreated) {
indexes.put(entry, entry);
}
}
return AgentXProtocol.AGENTX_SUCCESS;
}
class IndexEntry implements Comparable {
private int sessionID;
private Variable indexValue;
public IndexEntry(int sessionID, Variable indexValue) {
this.sessionID = sessionID;
this.indexValue = indexValue;
}
public int getSessionID() {
return sessionID;
}
public Variable getIndexValue() {
return indexValue;
}
public int hashCode() {
return indexValue.hashCode();
}
public boolean equals(Object o) {
if (o instanceof IndexEntry) {
return ((indexValue.equals(((IndexEntry)o).indexValue)) &&
(sessionID == ((IndexEntry)o).sessionID));
}
else if (o instanceof Variable) {
return indexValue.equals(o);
}
return false;
}
public int compareTo(Object o) {
OID indexOID = indexValue.toSubIndex(true);
if (o instanceof IndexEntry) {
return indexOID.compareTo(((IndexEntry)o).indexValue.toSubIndex(true));
}
else if (o instanceof Variable) {
return indexOID.compareTo(((Variable)o).toSubIndex(true));
}
throw new ClassCastException(o.getClass()+" != (IndexEntry or Variable)");
}
}
class IndexRegistryEntry implements Comparable {
private OctetString context;
private VariableBinding indexType;
private SortedMap indexValues = new TreeMap(new IndexComparator());
private SortedMap usedValues = new TreeMap(new IndexComparator());
public IndexRegistryEntry(OctetString context, VariableBinding indexType) {
this.context = (context == null) ? new OctetString() : context;
this.indexType = indexType;
}
public synchronized int allocate(int sessionID,
Variable indexValue, boolean testOnly) {
if (indexValue.getSyntax() != indexType.getSyntax()) {
return AgentXProtocol.AGENTX_INDEX_WRONG_TYPE;
}
else if (indexValues.get(indexValue) != null) {
return AgentXProtocol.AGENTX_INDEX_ALREADY_ALLOCATED;
}
else {
if (!testOnly) {
IndexEntry newEntry = new IndexEntry(sessionID, indexValue);
indexValues.put(newEntry, newEntry);
}
return AgentXProtocol.AGENTX_SUCCESS;
}
}
public synchronized int release(int sessionID,
Variable indexValue, boolean testOnly) {
IndexEntry removeKey = new IndexEntry(sessionID, indexValue);
IndexEntry contained = (IndexEntry) indexValues.get(removeKey);
if ((contained != null) && (contained.getSessionID() == sessionID)) {
if (!testOnly) {
Object r = indexValues.remove(contained);
usedValues.put(r,r);
}
return AgentXProtocol.AGENTX_SUCCESS;
}
return AgentXProtocol.AGENTX_INDEX_NOT_ALLOCATED;
}
public synchronized void release(int sessionID) {
for (Iterator it = indexValues.values().iterator(); it.hasNext();) {
IndexEntry entry = (IndexEntry) it.next();
if (entry.getSessionID() == sessionID) {
it.remove();
usedValues.put(entry, entry);
}
}
}
public int compareTo(Object o) {
IndexRegistryEntry other = (IndexRegistryEntry)o;
int c = context.compareTo(other.context);
if (c == 0) {
c = indexType.getOid().compareTo(other.indexType.getOid());
}
return c;
}
public int hashCode() {
return indexType.getOid().hashCode()+
((context == null)?0:context.hashCode());
}
public boolean equals(Object o) {
if (o instanceof IndexRegistryEntry) {
return indexType.getOid().equals(
((IndexRegistryEntry)o).indexType.getOid());
}
return false;
}
public VariableBinding getIndexType() {
return indexType;
}
public OctetString getContext() {
return context;
}
public synchronized Variable newIndex(int sessionID, boolean testOnly) {
try {
IndexEntry last = null;
if (!usedValues.isEmpty()) {
last = (IndexEntry) usedValues.lastKey();
}
if (!indexValues.isEmpty()) {
IndexEntry lastAllocated = (IndexEntry) indexValues.lastKey();
if (last == null) {
last = lastAllocated;
}
else if (lastAllocated.compareTo(last) > 0) {
last = lastAllocated;
}
}
else if (last == null) {
return anyIndex(sessionID, testOnly);
}
OID nextIndex = last.getIndexValue().toSubIndex(true);
nextIndex = nextIndex.nextPeer();
Variable nextIndexValue = (Variable)last.getIndexValue().clone();
nextIndexValue.fromSubIndex(nextIndex, true);
int status = allocate(sessionID, nextIndexValue, testOnly);
if (status != AgentXProtocol.AGENTX_SUCCESS) {
return null;
}
return nextIndexValue;
}
catch (Exception ex) {
LOGGER.error("Exception occurred while creating/allocating new index:"+
ex.getMessage(), ex);
return null;
}
}
public synchronized Variable anyIndex(int sessionID, boolean testOnly) {
try {
OID nextIndex;
if (usedValues.isEmpty()) {
if (indexValues.isEmpty()) {
nextIndex = indexType.getVariable().toSubIndex(true);
}
else {
nextIndex = ((IndexEntry)indexValues.lastKey()).
getIndexValue().toSubIndex(true);
}
}
else {
IndexEntry last = (IndexEntry) usedValues.firstKey();
nextIndex = last.getIndexValue().toSubIndex(true);
}
nextIndex = nextIndex.nextPeer();
Variable nextIndexValue = (Variable) indexType.getVariable().clone();
nextIndexValue.fromSubIndex(nextIndex, true);
int status = allocate(sessionID, nextIndexValue, testOnly);
if (status != AgentXProtocol.AGENTX_SUCCESS) {
return null;
}
return nextIndexValue;
}
catch (Exception ex) {
LOGGER.error("Exception occurred while creating/allocating"+
" any new index:"+ex.getMessage(), ex);
return null;
}
}
private class IndexComparator implements Comparator {
public int compare(Object o1, Object o2) {
Variable c1,c2;
if (o1 instanceof IndexEntry) {
c1 = ((IndexEntry)o1).getIndexValue();
}
else {
c1 = (Variable)o1;
}
if (o2 instanceof IndexEntry) {
c2 = ((IndexEntry)o2).getIndexValue();
}
else {
c2 = (Variable)o2;
}
return c1.compareTo(c2);
}
}
}
}