All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.remoting.callback.CallbackStore Maven / Gradle / Ivy

There is a newer version: 5.0.29.Final
Show newest version
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This 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 software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.remoting.callback;

import org.jboss.logging.Logger;
import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.serialization.SerializationStreamFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Map;

/**
 * Acts as a persistent list which writes Serializable objects to disk and will retrieve them
 * in same order in which they were added (FIFO).  Each file will be named according to the current
 * time (using System.currentTimeMillis() with the file suffix specified (see below).  When the
 * object is read and returned by calling the getNext() method, the file on disk for that object will
 * be deleted.  If for some reason the store VM crashes, the objects will still be available upon next startup.
 * 

* The attributes to make sure to configure are: *

* file path - this determins which directory to write the objects. The default value is the property value * of 'jboss.server.data.dir' and if this is not set, then will be 'data'. For example, might * be /jboss/server/default/data.

* file suffix - the file suffix to use for the file written for each object stored.

*

* This is also a service mbean, so can be run as a service within JBoss AS or stand alone. * * @author Tom Elrod */ public class CallbackStore implements CallbackStoreMBean { private static long previousTimestamp; private static int timestampCounter; private String filePath = null; private String fileSuffix = "ser"; private boolean isStarted = false; private boolean purgeOnShutdown = false; private String serializationType = "java"; /** * Key for setting which directory to write the callback objects. * The default value is the property value of 'jboss.server.data.dir' and if this is not set, * then will be 'data'. Will then append 'remoting' and the callback client's session id. * An example would be 'data\remoting\5c4o05l-9jijyx-e5b6xyph-1-e5b6xyph-2'. */ public static final String FILE_PATH_KEY = "StoreFilePath"; /** * Key for setting the file suffix to use for the callback objects written to disk. The default value is "ser". */ public static final String FILE_SUFFIX_KEY = "StoreFileSuffix"; private static final Logger log = Logger.getLogger(CallbackStore.class); /** * Default store constructor. */ public CallbackStore() { } /** * Store constructor. * * @param purgeOnDestroy if true, will remove all persisted objects from disk on when destroy() is called, else * will leave the files (which is the default behaviour). */ public CallbackStore(boolean purgeOnDestroy) { this.purgeOnShutdown = purgeOnDestroy; } /** * Will get the file path value (if not already set will just use the * default setting) and will create the directory specified by the file path * if it does not already exist. * * @throws Exception */ public void start() throws Exception { if (!isStarted) { // need to figure the best place to store on disk if (filePath == null) { filePath = System.getProperty("jboss.server.data.dir", "data"); } File storeFile = new File(filePath); if (!storeFile.exists()) { boolean madeDir = storeFile.mkdirs(); if (!madeDir) { throw new IOException("Can not create directory for store. Path given: " + filePath); } } isStarted = true; } } /** * Sets if store should clean up persisted files when shutdown (destroy()). * * @param purgeOnShutdown */ public void setPurgeOnShutdown(boolean purgeOnShutdown) { this.purgeOnShutdown = purgeOnShutdown; } /** * Returns if store will clean up persisted files when shutdown (destroy()). * * @return */ public boolean getPurgeOnShutdown() { return purgeOnShutdown; } /** * This is a no op method, but needed in order to be used as a service within JBoss AS. * * @throws Exception */ public void create() throws Exception { } /** * This will allow for change of file suffix and file path and then may start again * using these new values. However, any object already written out using the old * values will be lost as will not longer be accessible if these attributes are changed while stopped. */ public void stop() { isStarted = false; } /** * If purgeOnDestroy is true, will remove files upon shutdown. */ public void destroy() { if (purgeOnShutdown) { purgeFiles(); } } public void purgeFiles() { String[] fileList = getObjectFileList(); String fileToDelete = null; for (int x = 0; x < fileList.length; x++) { try { fileToDelete = filePath + System.getProperty("file.separator") + fileList[x]; File currentFile = new File(fileToDelete); boolean deleted = currentFile.delete(); if (!deleted) { log.warn("Error purging file " + fileToDelete); } } catch (Exception e) { log.warn("Error purging file " + fileToDelete); } } } /** * Will use the values in the map to set configuration. This will not change behaviour of store until * has been stopped and then started (if has not been started, will take effect upon start). * The keys for the map are FILE_PATH_KEY and FILE_SUFFIX_KEY. * * @param config */ public void setConfig(Map config) { if (config != null) { String newFilePath = (String) config.get(FILE_PATH_KEY); if (newFilePath != null) { filePath = newFilePath; } String newFileSuffix = (String) config.get(FILE_SUFFIX_KEY); if (newFileSuffix != null) { fileSuffix = newFileSuffix; } String newSerializationType = (String) config.get(InvokerLocator.SERIALIZATIONTYPE); if (newSerializationType != null) { serializationType = newSerializationType; } } } /** * Gets the file path for the directory where the objects will be stored. * * @return */ public String getStoreFilePath() { return filePath; } /** * Sets teh file path for the directory where the objects will be stored. * * @param filePath */ public void setStoreFilePath(String filePath) { this.filePath = filePath; } /** * Gets the file suffix for each of the files that objects will be persisted to. * * @return */ public String getStoreFileSuffix() { return fileSuffix; } /** * Sets the file suffix for each of the files that objects will be persisted to. * * @param fileSuffix */ public void setStoreFileSuffix(String fileSuffix) { this.fileSuffix = fileSuffix; } /** * Getst the number of objects stored and available. * * @return */ public int size() { verifyStarted(); String[] objectFileList = getObjectFileList(); if (objectFileList != null) { return objectFileList.length; } else { return 0; } } private void verifyStarted() { if (!isStarted) { throw new RuntimeException("Can not call upon this store method before it has been started."); } } /** * Will look through the files in the store directory for the oldest object serialized to disk, load it, * delete the file, and return the deserialized object. * Important to note that once this object is returned from this method, it is gone forever from this * store and will not be able to retrieve it again without adding it back. * * @return * @throws IOException */ public Object getNext() throws IOException { verifyStarted(); Object obj = null; String objectFilePath = null; synchronized (filePath) { String[] objectFileList = getObjectFileList(); FileInputStream inFile = null; ObjectInputStream in = null; if (objectFileList != null && objectFileList.length > 0) { try { // only getting the first one, which will be first one entered since the getting // of the list is automatically ordered by the OS and all file names are numeric by time. objectFilePath = filePath + System.getProperty("file.separator") + objectFileList[0]; inFile = new FileInputStream(objectFilePath); in = SerializationStreamFactory.getManagerInstance(serializationType).createRegularInput(inFile); try { obj = in.readObject(); } catch (ClassNotFoundException e) { throw new IOException("Error loading persisted object. Could not load class (" + e.getMessage() + ")."); } } finally { if (inFile != null) { try { inFile.close(); } catch (IOException ioe) { log.debug("Error closing FileInputStream.", ioe); } } if (in != null) { try { in.close(); } catch (IOException ioe) { log.debug("Error closing ObjectInputStream.", ioe); } } if (objectFilePath != null) { // now remove the file File objectFile = new File(objectFilePath); boolean isDeleted = objectFile.delete(); if (log.isTraceEnabled()) { log.trace("object file (" + objectFilePath + ") has been deleted - " + isDeleted); } } } } } return obj; } private String[] getObjectFileList() { File storePath = new File(filePath); String[] objectFileList = storePath.list(new StoreFileFilter()); Arrays.sort(objectFileList); return objectFileList; } /** * Persists the serializable object passed to the directory specified. The file name will be the current time * in milliseconds (vis System.currentTimeMillis()) with the specified suffix. This object can later be * retrieved using the getNext() method, but objects will be returned in the order that they were added (FIFO). * * @param object * @throws IOException */ public void add(Serializable object) throws IOException { verifyStarted(); synchronized (filePath) { long currentTimestamp = System.currentTimeMillis(); if (previousTimestamp == currentTimestamp) { timestampCounter++; } else { previousTimestamp = currentTimestamp; timestampCounter = 0; } StringBuffer path = new StringBuffer(filePath); path.append(System.getProperty("file.separator")).append(String.valueOf(currentTimestamp)); path.append("-").append(timestampCounter).append(".").append(fileSuffix); File storeFile = new File(path.toString()); FileOutputStream outFile = null; ObjectOutputStream out = null; try { outFile = new FileOutputStream(storeFile, false); out = SerializationStreamFactory.getManagerInstance(serializationType).createOutput(outFile); out.writeObject(object); out.flush(); } finally { if (outFile != null) { try { outFile.close(); } catch (IOException ioe) { log.debug("Error closing FileInputStream.", ioe); } } if (out != null) { try { out.close(); } catch (IOException ioe) { log.debug("Error closing ObjectInputStream.", ioe); } } } } } public class StoreFileFilter implements FilenameFilter { /** * Tests if a specified file should be included in a file list. * * @param dir the directory in which the file was found. * @param name the name of the file. * @return true if and only if the name should be included in the file list; false * otherwise. */ public boolean accept(File dir, String name) { if (name.endsWith(fileSuffix)) { return true; } else { return false; } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy