/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.management.snmp.util;
import com.sun.jmx.snmp.SnmpOid;
import com.sun.jmx.mbeanserver.Util;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;
import java.util.List;
import java.util.Iterator;
import java.lang.ref.WeakReference;
This abstract class implements a weak cache that holds table data, for
a table whose data is obtained from a list where a name can be obtained
for each item in the list.
This object maintains a map between an entry name and its associated
SnmpOid index, so that a given entry is always associated to the same
index.
NOTE: This class is not synchronized, subclasses must implement
the appropriate synchronization whwn needed.
/**
* This abstract class implements a weak cache that holds table data, for
* a table whose data is obtained from a list where a name can be obtained
* for each item in the list.
* <p>This object maintains a map between an entry name and its associated
* SnmpOid index, so that a given entry is always associated to the same
* index.</p>
* <p><b>NOTE: This class is not synchronized, subclasses must implement
* the appropriate synchronization whwn needed.</b></p>
**/
public abstract class SnmpNamedListTableCache extends SnmpListTableCache {
This map associate an entry name with the SnmpOid index that's
been allocated for it.
/**
* This map associate an entry name with the SnmpOid index that's
* been allocated for it.
**/
protected TreeMap<String, SnmpOid> names = new TreeMap<>();
The last allocate index.
/**
* The last allocate index.
**/
protected long last = 0;
true if the index has wrapped.
/**
* true if the index has wrapped.
**/
boolean wrapped = false;
Returns the key to use as name for the given item.
This method is called by getIndex(Object, List, int, Object)
. The given item is expected to be always associated with
the same name.
Params: - context – The context passed to
updateCachedDatas(Object, List<?>)
. - rawDatas – Raw table datas passed to
updateCachedDatas(Object, List<?>)
. - rank – Rank of the given item in the
rawDatas list iterator.
- item – The raw data object for which a key name must be determined.
/**
* Returns the key to use as name for the given <var>item</var>.
* <br>This method is called by {@link #getIndex(Object,List,int,Object)}.
* The given <var>item</var> is expected to be always associated with
* the same name.
* @param context The context passed to
* {@link #updateCachedDatas(Object,List)}.
* @param rawDatas Raw table datas passed to
* {@link #updateCachedDatas(Object,List)}.
* @param rank Rank of the given <var>item</var> in the
* <var>rawDatas</var> list iterator.
* @param item The raw data object for which a key name must be determined.
**/
protected abstract String getKey(Object context, List<?> rawDatas,
int rank, Object item);
Find a new index for the entry corresponding to the
given item.
This method is called by getIndex(Object, List, int, Object)
when a new index needs to be allocated for an item. The
index returned must not be already in used.
Params: - context – The context passed to
updateCachedDatas(Object, List<?>)
. - rawDatas – Raw table datas passed to
updateCachedDatas(Object, List<?>)
. - rank – Rank of the given item in the
rawDatas list iterator.
- item – The raw data object for which an index must be determined.
/**
* Find a new index for the entry corresponding to the
* given <var>item</var>.
* <br>This method is called by {@link #getIndex(Object,List,int,Object)}
* when a new index needs to be allocated for an <var>item</var>. The
* index returned must not be already in used.
* @param context The context passed to
* {@link #updateCachedDatas(Object,List)}.
* @param rawDatas Raw table datas passed to
* {@link #updateCachedDatas(Object,List)}.
* @param rank Rank of the given <var>item</var> in the
* <var>rawDatas</var> list iterator.
* @param item The raw data object for which an index must be determined.
**/
protected SnmpOid makeIndex(Object context, List<?> rawDatas,
int rank, Object item) {
// check we are in the limits of an unsigned32.
if (++last > 0x00000000FFFFFFFFL) {
// we just wrapped.
log.debug("makeIndex", "Index wrapping...");
last = 0;
wrapped=true;
}
// If we never wrapped, we can safely return last as new index.
if (!wrapped) return new SnmpOid(last);
// We wrapped. We must look for an unused index.
for (int i=1;i < 0x00000000FFFFFFFFL;i++) {
if (++last > 0x00000000FFFFFFFFL) last = 1;
final SnmpOid testOid = new SnmpOid(last);
// Was this index already in use?
if (names == null) return testOid;
if (names.containsValue(testOid)) continue;
// Have we just used it in a previous iteration?
if (context == null) return testOid;
if (((Map)context).containsValue(testOid)) continue;
// Ok, not in use.
return testOid;
}
// all indexes are in use! we're stuck.
// // throw new IndexOutOfBoundsException("No index available.");
// better to return null and log an error.
return null;
}
Call getKey(Object, List<?>, int, Object)
in order to get the item name. Then check whether an index was already allocated for the entry by that name. If yes return it. Otherwise, call makeIndex(Object, List, int, Object)
to compute a new index for that entry. Finally store the association between the name and index in the context TreeMap. Params: - context – The context passed to
updateCachedDatas(Object, List<?>)
. It is expected to be an instance of TreeMap
. - rawDatas – Raw table datas passed to
updateCachedDatas(Object, List<?>)
. - rank – Rank of the given item in the
rawDatas list iterator.
- item – The raw data object for which an index must be determined.
/**
* Call {@link #getKey(Object,List,int,Object)} in order to get
* the item name. Then check whether an index was already allocated
* for the entry by that name. If yes return it. Otherwise, call
* {@link #makeIndex(Object,List,int,Object)} to compute a new
* index for that entry.
* Finally store the association between
* the name and index in the context TreeMap.
* @param context The context passed to
* {@link #updateCachedDatas(Object,List)}.
* It is expected to
* be an instance of {@link TreeMap}.
* @param rawDatas Raw table datas passed to
* {@link #updateCachedDatas(Object,List)}.
* @param rank Rank of the given <var>item</var> in the
* <var>rawDatas</var> list iterator.
* @param item The raw data object for which an index must be determined.
**/
protected SnmpOid getIndex(Object context, List<?> rawDatas,
int rank, Object item) {
final String key = getKey(context,rawDatas,rank,item);
final Object index = (names==null||key==null)?null:names.get(key);
final SnmpOid result =
((index != null)?((SnmpOid)index):makeIndex(context,rawDatas,
rank,item));
if ((context != null) && (key != null) && (result != null)) {
Map<Object, Object> map = Util.cast(context);
map.put(key,result);
}
log.debug("getIndex","key="+key+", index="+result);
return result;
}
Allocate a new TreeMap
to serve as context, then call SnmpListTableCache.updateCachedDatas(Object, List<?>)
, and finally replace the names
TreeMap by the new allocated TreeMap. Params: - rawDatas – The table datas from which the cached data will be
computed.
/**
* Allocate a new {@link TreeMap} to serve as context, then
* call {@link SnmpListTableCache#updateCachedDatas(Object,List)}, and
* finally replace the {@link #names} TreeMap by the new allocated
* TreeMap.
* @param rawDatas The table datas from which the cached data will be
* computed.
**/
protected SnmpCachedData updateCachedDatas(Object context, List<?> rawDatas) {
TreeMap<String,SnmpOid> ctxt = new TreeMap<>();
final SnmpCachedData result =
super.updateCachedDatas(context,rawDatas);
names = ctxt;
return result;
}
Load a list of raw data from which to build the cached data.
This method is called when nothing is found in the request
contextual cache.
Params: - userData – The request contextual cache allocated by the
JvmContextFactory
.
/**
* Load a list of raw data from which to build the cached data.
* This method is called when nothing is found in the request
* contextual cache.
* @param userData The request contextual cache allocated by
* the {@link JvmContextFactory}.
*
**/
protected abstract List<?> loadRawDatas(Map<Object,Object> userData);
The name under which the raw data is to be found/put in
the request contextual cache.
/**
*The name under which the raw data is to be found/put in
* the request contextual cache.
**/
protected abstract String getRawDatasKey();
Get a list of raw data from which to build the cached data.
Obtains a list of raw data by first looking it up in the
request contextual cache userData under the given
key. If nothing is found in the cache, calls loadRawDatas(Map<Object,Object>)
to obtain a new rawData list, and cache the result in userData under key.
Params: - userData – The request contextual cache allocated by the
JvmContextFactory
. - key – The name under which the raw data is to be found/put in
the request contextual cache.
/**
* Get a list of raw data from which to build the cached data.
* Obtains a list of raw data by first looking it up in the
* request contextual cache <var>userData</var> under the given
* <var>key</var>. If nothing is found in the cache, calls
* {@link #loadRawDatas(Map)} to obtain a new rawData list,
* and cache the result in <var>userData</var> under <var>key</var>.
* @param userData The request contextual cache allocated by
* the {@link JvmContextFactory}.
* @param key The name under which the raw data is to be found/put in
* the request contextual cache.
*
**/
protected List<?> getRawDatas(Map<Object, Object> userData, String key) {
List<?> rawDatas = null;
// Look for memory manager list in request contextual cache.
if (userData != null)
rawDatas = (List<?>)userData.get(key);
if (rawDatas == null) {
// No list in contextual cache, get it from API
rawDatas = loadRawDatas(userData);
// Put list in cache...
if (rawDatas != null && userData != null)
userData.put(key, rawDatas);
}
return rawDatas;
}
Update cahed datas. Obtains a List
of raw datas by calling getRawDatas((Map)context,getRawDatasKey())
.
Then allocate a new TreeMap
to serve as temporary map between names and indexes, and call updateCachedDatas(Object, List<?>)
with that temporary map as context.
Finally replaces the names
TreeMap by the temporary TreeMap. Params: - context – The request contextual cache allocated by the
JvmContextFactory
.
/**
* Update cahed datas.
* Obtains a {@link List} of raw datas by calling
* {@link #getRawDatas(Map,String) getRawDatas((Map)context,getRawDatasKey())}.<br>
* Then allocate a new {@link TreeMap} to serve as temporary map between
* names and indexes, and call {@link #updateCachedDatas(Object,List)}
* with that temporary map as context.<br>
* Finally replaces the {@link #names} TreeMap by the temporary
* TreeMap.
* @param context The request contextual cache allocated by the
* {@link JvmContextFactory}.
**/
protected SnmpCachedData updateCachedDatas(Object context) {
final Map<Object, Object> userData =
(context instanceof Map)?Util.<Map<Object, Object>>cast(context):null;
// Look for memory manager list in request contextual cache.
final List<?> rawDatas = getRawDatas(userData,getRawDatasKey());
log.debug("updateCachedDatas","rawDatas.size()=" +
((rawDatas==null)?"<no data>":""+rawDatas.size()));
TreeMap<String,SnmpOid> ctxt = new TreeMap<>();
final SnmpCachedData result =
super.updateCachedDatas(ctxt,rawDatas);
names = ctxt;
return result;
}
static final MibLogger log = new MibLogger(SnmpNamedListTableCache.class);
}