org.snmp4j.agent.db.MOXodusPersistenceProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of snmp4j-agent-db Show documentation
Show all versions of snmp4j-agent-db Show documentation
Database persistency extension for the SNMP4J-Agent API
/*_############################################################################
_##
_## SNMP4J-Agent-DB 3 - MOXodusPersistenceProvider.java
_##
_## Copyright (C) 2017-2018 Frank Fock (SNMP4J.org)
_##
_## Licensed 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.snmp4j.agent.db;
import jetbrains.exodus.ArrayByteIterable;
import jetbrains.exodus.ByteIterable;
import jetbrains.exodus.bindings.IntegerBinding;
import jetbrains.exodus.bindings.StringBinding;
import jetbrains.exodus.env.*;
import org.snmp4j.agent.MOServer;
import org.snmp4j.agent.cfg.EngineBootsProvider;
import org.snmp4j.agent.cfg.EngineIdProvider;
import org.snmp4j.agent.io.ImportMode;
import org.snmp4j.agent.io.MOPersistenceProvider;
import org.snmp4j.smi.OctetString;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
/**
* The {@link MOXodusPersistenceProvider} implements a {@link MOPersistenceProvider} that uses a JetBrains Xodus
* database for persistent storage of {@link org.snmp4j.agent.RandomAccessManagedObject}s.
* Using {@link org.snmp4j.agent.RandomAccessManagedObject} peristence with this {@link MOXodusPersistenceProvider} has
* the following advantages:
*
* - Less disk space usage than with {@link org.snmp4j.agent.io.DefaultMOPersistenceProvider}
* - Any Managed object changes are store via {@link org.snmp4j.agent.mo.MOChangeListener} and
* {@link org.snmp4j.agent.mo.MOTableRowListener} persistently into the database immediately.
* - Concurrent access to storage is safe.
*
* See {@link org.snmp4j.agent.io.MOServerPersistence} for sample code and further usage details.
*
* @author Frank Fock
* @version 3.0
*/
public class MOXodusPersistenceProvider implements MOPersistenceProvider, EngineBootsProvider, EngineIdProvider {
/**
* Engine store ID must be longer than 32 characters - otherwise name could clash with a SNMP context.
*/
private final static String ENGINE_STORE_ID = "_SNMP4J-Agent_EngineStore_______v3.0";
private static final String BOOTS_COUNTER_KEY = "BootsCounter";
private static final String ENGINE_ID_KEY = "EngineID";
private MOXodusPersistence defaultPersistence;
/**
* Creates a {@link MOXodusPersistenceProvider} based with a provided default {@link MOXodusPersistence} handler
* that provides the default storage access operations and listens for
* {@link org.snmp4j.agent.RandomAccessManagedObject} update events
* (see {@link MOXodusPersistence#registerChangeListenersWithServer(MOServer)} for details).
*
* Additional {@link MOXodusPersistence} can be created on the fly, with {@link #store(String)}.
*
* @param defaultPersistence
* the default persistence handler.
*/
public MOXodusPersistenceProvider(MOXodusPersistence defaultPersistence) {
this.defaultPersistence = defaultPersistence;
}
/**
* Restore (load) agent state from the specified URI (can be as simple as
* a file path).
*
* @param uri a string pointing to the persistent storage from which the agent state
* should be restored from. The format of he string is specified by the
* persistence provider. A null
value can be specified to
* let the persistence provider use its default URI. If that default URI
* is null
too, a NullPointerException
will be
* thrown.
* @param importMode specifies how the agent's current state should be update while
* restoring a previous state.
* @throws IOException if the restore operation fails.
* @since 1.2
*/
@Override
public void restore(String uri, int importMode) throws IOException {
MOXodusPersistence persistence = defaultPersistence;
boolean specialURI = (uri != null && !uri.equals(getDefaultURI()));
if (specialURI) {
persistence = new MOXodusPersistence(defaultPersistence.getMOServer(),
Environments.newInstance(getFilePath(uri)));
}
persistence.load(ImportMode.values()[importMode]);
if (specialURI) {
persistence.getEnvironment().close();
}
}
/**
* Stores the current agent state to persistent storage specified by the
* supplied URI.
*
* @param uri a string pointing to the persistent storage from which the agent state
* should be stored to. The format of the string is specified by the
* persistence provider. A null
value can be specified to
* let the persistence provider use its default URI. If that default URI
* is null
too, a NullPointerException
will be
* thrown.
* @throws IOException if the store operation fails.
* @since 1.2
*/
@Override
public void store(String uri) throws IOException {
MOXodusPersistence persistence = defaultPersistence;
boolean specialURI = (uri != null && !uri.equals(getDefaultURI()));
if (specialURI) {
persistence = new MOXodusPersistence(defaultPersistence.getMOServer(),
Environments.newInstance(getFilePath(uri)));
}
persistence.save();
if (specialURI) {
persistence.getEnvironment().close();
}
}
/**
* Checks whether the supplied URI string is valid for this persistence
* provider.
*
* @param uriString a string identifying a persistent storage location for this storage
* provider.
* @return true
if the uri
is valid, false
* otherwise.
* @since 1.2
*/
@Override
public boolean isValidPersistenceURI(String uriString) {
try {
URI uri = new URI(uriString);
if (uri.getScheme() == null || uri.getScheme().equals("file")) {
return true;
}
return false;
} catch (URISyntaxException e) {
return false;
}
}
/**
* Returns an unique ID of the persistence provider which should identify the
* format and type of the persistence provider.
*
* @return an 1-32 character long string that identifies the persistence provider.
* @since 1.2
*/
@Override
public String getPersistenceProviderID() {
return "default";
}
/**
* Gets the URI of the default persistent storage for this provider.
*
* @return the URI (e.g. file path) for the default persistent storage location of
* this provider. A provider may use a different one. A null
* value indicates that there is no default location.
*/
@Override
public String getDefaultURI() {
return defaultPersistence.getEnvironment().getLocation();
}
private String getFilePath(String uri) {
File f;
if (uri.toUpperCase().startsWith("FILE:")) {
URI u = URI.create(uri);
f = new File(u);
}
else {
f = new File(uri);
}
return f.getPath();
}
/**
* Returns the current engine boot counter value incremented by one. If
* that number would by greater than 2^31-1 then one is returned. The
* engine boots provider has to make sure that the returned value is
* persistently stored before the method returns.
*
* @return the last engine boots counter incremented by one.
*/
@Override
public int updateEngineBoots() {
Environment environment = defaultPersistence.getEnvironment();
Transaction txn = environment.beginExclusiveTransaction();
Store store = environment.openStore(ENGINE_STORE_ID, StoreConfig.WITHOUT_DUPLICATES, txn);
ByteIterable bootsCounterKey = StringBinding.stringToEntry(BOOTS_COUNTER_KEY);
ByteIterable bootsCounterRaw = store.get(txn, bootsCounterKey);
int bootsCounter = 0;
if (bootsCounterRaw != null) {
bootsCounter = IntegerBinding.entryToInt(bootsCounterRaw);
bootsCounter++;
store.put(txn, bootsCounterKey, IntegerBinding.intToEntry(bootsCounter));
}
txn.flush();
txn.commit();
return bootsCounter;
}
/**
* Returns current engine boot counter value.
*
* @return the last engine boots counter.
*/
@Override
public int getEngineBoots() {
Environment environment = defaultPersistence.getEnvironment();
Transaction txn = environment.beginReadonlyTransaction();
Store store = environment.openStore(ENGINE_STORE_ID, StoreConfig.WITHOUT_DUPLICATES, txn);
ByteIterable bootsCounterKey = StringBinding.stringToEntry(BOOTS_COUNTER_KEY);
ByteIterable bootsCounterRaw = store.get(txn, bootsCounterKey);
int bootsCounter = 0;
if (bootsCounterRaw != null) {
bootsCounter = IntegerBinding.entryToInt(bootsCounterRaw);
}
txn.abort();
return bootsCounter;
}
@Override
public OctetString getEngineId(OctetString defaultEngineID) {
Environment environment = defaultPersistence.getEnvironment();
Transaction txn = environment.beginExclusiveTransaction();
Store store = environment.openStore(ENGINE_STORE_ID, StoreConfig.WITHOUT_DUPLICATES, txn);
ByteIterable engineIdKey = StringBinding.stringToEntry(ENGINE_ID_KEY);
ByteIterable engineIdRaw = store.get(txn, engineIdKey);
byte[] engineID = null;
if (engineIdRaw != null) {
engineID = new byte[engineIdRaw.getLength()];
System.arraycopy(engineIdRaw.getBytesUnsafe(), 0, engineID, 0, engineID.length);
}
else if (defaultEngineID != null) {
engineID = defaultEngineID.getValue();
resetEngineId(txn, store, engineID);
}
txn.flush();
txn.commit();
return (engineIdRaw != null) ? new OctetString(engineID) : defaultEngineID;
}
@Override
public void resetEngineId(OctetString engineId) {
Environment environment = defaultPersistence.getEnvironment();
Transaction txn = environment.beginExclusiveTransaction();
Store store = environment.openStore(ENGINE_STORE_ID, StoreConfig.WITHOUT_DUPLICATES, txn);
resetEngineId(txn, store, engineId.getValue());
}
private void resetEngineId(Transaction txn, Store store, byte[] engineID) {
ByteIterable engineIdKey = StringBinding.stringToEntry(ENGINE_ID_KEY);
store.put(txn, engineIdKey, new ArrayByteIterable(engineID));
ByteIterable bootsCounterKey = StringBinding.stringToEntry(BOOTS_COUNTER_KEY);
store.put(txn, bootsCounterKey, IntegerBinding.intToEntry(1));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy