001 /* ============================================================
002 * JRobin : Pure java implementation of RRDTool's functionality
003 * ============================================================
004 *
005 * Project Info: http://www.jrobin.org
006 * Project Lead: Sasa Markovic (saxon@jrobin.org);
007 *
008 * (C) Copyright 2003-2005, by Sasa Markovic.
009 *
010 * Developers: Sasa Markovic (saxon@jrobin.org)
011 *
012 *
013 * This library is free software; you can redistribute it and/or modify it under the terms
014 * of the GNU Lesser General Public License as published by the Free Software Foundation;
015 * either version 2.1 of the License, or (at your option) any later version.
016 *
017 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
018 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
019 * See the GNU Lesser General Public License for more details.
020 *
021 * You should have received a copy of the GNU Lesser General Public License along with this
022 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
023 * Boston, MA 02111-1307, USA.
024 */
025
026 package org.jrobin.core;
027
028 import java.io.IOException;
029 import java.util.HashMap;
030
031 /**
032 * Base (abstract) backend factory class which holds references to all concrete
033 * backend factories and defines abstract methods which must be implemented in
034 * all concrete factory implementations.<p>
035 * <p/>
036 * Factory classes are used to create concrete {@link RrdBackend} implementations.
037 * Each factory creates unlimited number of specific backend objects.
038 * <p/>
039 * JRobin supports four different backend types (backend factories) out of the box:<p>
040 * <ul>
041 * <li>{@link RrdFileBackend}: objects of this class are created from the
042 * {@link RrdFileBackendFactory} class. This was the default backend used in all
043 * JRobin releases before 1.4.0 release. It uses java.io.* package and RandomAccessFile class to store
044 * RRD data in files on the disk.
045 * <p/>
046 * <li>{@link RrdSafeFileBackend}: objects of this class are created from the
047 * {@link RrdSafeFileBackendFactory} class. It uses java.io.* package and RandomAccessFile class to store
048 * RRD data in files on the disk. This backend is SAFE:
049 * it locks the underlying RRD file during update/fetch operations, and caches only static
050 * parts of a RRD file in memory. Therefore, this backend is safe to be used when RRD files should
051 * be shared <b>between several JVMs</b> at the same time. However, this backend is *slow* since it does
052 * not use fast java.nio.* package (it's still based on the RandomAccessFile class).
053 * <p/>
054 * <li>{@link RrdNioBackend}: objects of this class are created from the
055 * {@link RrdNioBackendFactory} class. The backend uses java.io.* and java.nio.*
056 * classes (mapped ByteBuffer) to store RRD data in files on the disk. This is the default backend
057 * since 1.4.0 release.
058 * <p/>
059 * <li>{@link RrdMemoryBackend}: objects of this class are created from the
060 * {@link RrdMemoryBackendFactory} class. This backend stores all data in memory. Once
061 * JVM exits, all data gets lost. The backend is extremely fast and memory hungry.
062 * </ul>
063 * <p/>
064 * Each backend factory is identifed by its {@link #getFactoryName() name}. Constructors
065 * are provided in the {@link RrdDb} class to create RrdDb objects (RRD databases)
066 * backed with a specific backend.<p>
067 * <p/>
068 * See javadoc for {@link RrdBackend} to find out how to create your custom backends.
069 */
070 public abstract class RrdBackendFactory {
071 private static final HashMap<String, RrdBackendFactory> factories = new HashMap<String, RrdBackendFactory>();
072 private static RrdBackendFactory defaultFactory;
073
074 static {
075 try {
076 RrdFileBackendFactory fileFactory = new RrdFileBackendFactory();
077 registerFactory(fileFactory);
078 RrdMemoryBackendFactory memoryFactory = new RrdMemoryBackendFactory();
079 registerFactory(memoryFactory);
080 RrdNioBackendFactory nioFactory = new RrdNioBackendFactory();
081 registerFactory(nioFactory);
082 RrdSafeFileBackendFactory safeFactory = new RrdSafeFileBackendFactory();
083 registerFactory(safeFactory);
084 selectDefaultFactory();
085 }
086 catch (RrdException e) {
087 throw new RuntimeException("FATAL: Cannot register RRD backend factories: " + e);
088 }
089 }
090
091 private static void selectDefaultFactory() throws RrdException {
092 String version = System.getProperty("java.version");
093 if (version == null || version.startsWith("1.3.") ||
094 version.startsWith("1.4.0") || version.startsWith("1.4.1")) {
095 setDefaultFactory("FILE");
096 }
097 else {
098 setDefaultFactory("NIO");
099 }
100 }
101
102 /**
103 * Returns backend factory for the given backend factory name.
104 *
105 * @param name Backend factory name. Initially supported names are:<p>
106 * <ul>
107 * <li><b>FILE</b>: Default factory which creates backends based on the
108 * java.io.* package. RRD data is stored in files on the disk
109 * <li><b>SAFE</b>: Default factory which creates backends based on the
110 * java.io.* package. RRD data is stored in files on the disk. This backend
111 * is "safe". Being safe means that RRD files can be safely shared between
112 * several JVM's.
113 * <li><b>NIO</b>: Factory which creates backends based on the
114 * java.nio.* package. RRD data is stored in files on the disk
115 * <li><b>MEMORY</b>: Factory which creates memory-oriented backends.
116 * RRD data is stored in memory, it gets lost as soon as JVM exits.
117 * </ul>
118 * @return Backend factory for the given factory name
119 * @throws RrdException Thrown if no factory with the given name
120 * is available.
121 */
122 public static synchronized RrdBackendFactory getFactory(String name) throws RrdException {
123 RrdBackendFactory factory = factories.get(name);
124 if (factory != null) {
125 return factory;
126 }
127 else {
128 throw new RrdException("No backend factory found with the name specified [" + name + "]");
129 }
130 }
131
132 /**
133 * Registers new (custom) backend factory within the JRobin framework.
134 *
135 * @param factory Factory to be registered
136 * @throws RrdException Thrown if the name of the specified factory is already
137 * used.
138 */
139 public static synchronized void registerFactory(RrdBackendFactory factory)
140 throws RrdException {
141 String name = factory.getFactoryName();
142 if (!factories.containsKey(name)) {
143 factories.put(name, factory);
144 }
145 else {
146 throw new RrdException("Backend factory of this name2 (" + name +
147 ") already exists and cannot be registered");
148 }
149 }
150
151 /**
152 * Registers new (custom) backend factory within the JRobin framework and sets this
153 * factory as the default.
154 *
155 * @param factory Factory to be registered and set as default
156 * @throws RrdException Thrown if the name of the specified factory is already
157 * used.
158 */
159 public static synchronized void registerAndSetAsDefaultFactory(RrdBackendFactory factory)
160 throws RrdException {
161 registerFactory(factory);
162 setDefaultFactory(factory.getFactoryName());
163 }
164
165 /**
166 * Returns the defaul backend factory. This factory is used to construct
167 * {@link RrdDb} objects if no factory is specified in the RrdDb constructor.
168 *
169 * @return Default backend factory.
170 */
171 public static RrdBackendFactory getDefaultFactory() {
172 return defaultFactory;
173 }
174
175 /**
176 * Replaces the default backend factory with a new one. This method must be called before
177 * the first RRD gets created. <p>
178 *
179 * @param factoryName Name of the default factory. Out of the box, JRobin supports four
180 * different RRD backends: "FILE" (java.io.* based), "SAFE" (java.io.* based - use this
181 * backend if RRD files may be accessed from several JVMs at the same time),
182 * "NIO" (java.nio.* based) and "MEMORY" (byte[] based).
183 * @throws RrdException Thrown if invalid factory name is supplied or not called before
184 * the first RRD is created.
185 */
186 public static void setDefaultFactory(String factoryName) throws RrdException {
187 // We will allow this only if no RRDs are created
188 if (!RrdBackend.isInstanceCreated()) {
189 defaultFactory = getFactory(factoryName);
190 }
191 else {
192 throw new RrdException("Could not change the default backend factory. " +
193 "This method must be called before the first RRD gets created");
194 }
195 }
196
197 /**
198 * Creates RrdBackend object for the given storage path.
199 *
200 * @param path Storage path
201 * @param readOnly True, if the storage should be accessed in read/only mode.
202 * False otherwise.
203 * @return Backend object which handles all I/O operations for the given storage path
204 * @throws IOException Thrown in case of I/O error.
205 */
206 protected abstract RrdBackend open(String path, boolean readOnly) throws IOException;
207
208 /**
209 * Method to determine if a storage with the given path already exists.
210 *
211 * @param path Storage path
212 * @return True, if such storage exists, false otherwise.
213 */
214 protected abstract boolean exists(String path) throws IOException;
215
216 /**
217 * Returns the name (primary ID) for the factory.
218 *
219 * @return Name of the factory.
220 */
221 public abstract String getFactoryName();
222 }