001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.transaction.file;
018
019 import java.io.ByteArrayInputStream;
020 import java.io.InputStream;
021 import java.io.OutputStream;
022
023 import org.apache.commons.transaction.util.LoggerFacade;
024
025 /**
026 * A resource manager for streamable objects stored in a file system that
027 * features additional administration commands.
028 *
029 * @version $Id: FileResourceManager.java 519647 2007-03-18 17:50:02Z
030 * ozeigermann $
031 */
032 public class VirtualAdminCommandsFileResourceManager extends
033 FileResourceManager implements ResourceManager,
034 ResourceManagerErrorCodes {
035
036 protected String virtualAdminPath = null;
037
038 public String getVirtualAdminPath() {
039 return virtualAdminPath;
040 }
041
042 public void setVirtualAdminPath(String virutalAdminPath) {
043 this.virtualAdminPath = virutalAdminPath;
044 }
045
046 /**
047 * Creates a new resource manager operation on the specified directories.
048 *
049 * @param storeDir
050 * directory where main data should go after commit
051 * @param workDir
052 * directory where transactions store temporary data
053 * @param urlEncodePath
054 * if set to <code>true</code> encodes all paths to allow for
055 * any kind of characters
056 * @param logger
057 * the logger to be used by this store
058 */
059 public VirtualAdminCommandsFileResourceManager(String storeDir,
060 String workDir, boolean urlEncodePath, LoggerFacade logger) {
061 this(storeDir, workDir, urlEncodePath, logger, false);
062 }
063
064 /**
065 * Creates a new resource manager operation on the specified directories.
066 *
067 * @param storeDir
068 * directory where main data should go after commit
069 * @param workDir
070 * directory where transactions store temporary data
071 * @param urlEncodePath
072 * if set to <code>true</code> encodes all paths to allow for
073 * any kind of characters
074 * @param logger
075 * the logger to be used by this store
076 * @param debug
077 * if set to <code>true</code> logs all locking information to
078 * "transaction.log" for debugging inspection
079 */
080 public VirtualAdminCommandsFileResourceManager(String storeDir,
081 String workDir, boolean urlEncodePath, LoggerFacade logger,
082 boolean debug) {
083 this(storeDir, workDir, urlEncodePath ? new URLEncodeIdMapper() : null,
084 new NoOpTransactionIdToPathMapper(), logger, debug);
085 }
086
087 /**
088 * Creates a new resource manager operation on the specified directories.
089 * This constructor is reintroduced for backwards API compatibility and is
090 * used by jakarta-slide.
091 *
092 * @param storeDir
093 * directory where main data should go after commit
094 * @param workDir
095 * directory where transactions store temporary data
096 * @param idMapper
097 * mapper for resourceId to path
098 * @param logger
099 * the logger to be used by this store
100 * @param debug
101 * if set to <code>true</code> logs all locking information to
102 * "transaction.log" for debugging inspection
103 */
104 public VirtualAdminCommandsFileResourceManager(String storeDir,
105 String workDir, ResourceIdToPathMapper idMapper,
106 LoggerFacade logger, boolean debug) {
107 this(storeDir, workDir, idMapper, new NoOpTransactionIdToPathMapper(),
108 logger, debug);
109 }
110
111 /**
112 * Creates a new resource manager operation on the specified directories.
113 *
114 * @param storeDir
115 * directory where main data should go after commit
116 * @param workDir
117 * directory where transactions store temporary data
118 * @param idMapper
119 * mapper for resourceId to path
120 * @param txIdMapper
121 * mapper for transaction id to path
122 * @param logger
123 * the logger to be used by this store
124 * @param debug
125 * if set to <code>true</code> logs all locking information to
126 * "transaction.log" for debugging inspection
127 */
128 public VirtualAdminCommandsFileResourceManager(String storeDir,
129 String workDir, ResourceIdToPathMapper idMapper,
130 TransactionIdToPathMapper txIdMapper, LoggerFacade logger,
131 boolean debug) {
132 super(workDir, storeDir, idMapper, txIdMapper, logger, debug);
133 }
134
135 public boolean resourceExists(Object resourceId)
136 throws ResourceManagerException {
137 if (isVirtualAdminId(resourceId)) {
138 logger
139 .logFine("Faking existence of virtual administration command");
140 return true;
141 }
142
143 return super.resourceExists(resourceId);
144 }
145
146 public boolean resourceExists(Object txId, Object resourceId)
147 throws ResourceManagerException {
148 if (isVirtualAdminId(resourceId)) {
149 logger
150 .logFine("Faking existence of virtual administration command");
151 return true;
152 }
153
154 return super.resourceExists(txId, resourceId);
155 }
156
157 public void deleteResource(Object txId, Object resourceId)
158 throws ResourceManagerException {
159
160 checkForVirtualAdminCommand(resourceId);
161
162 super.deleteResource(txId, resourceId);
163 }
164
165 public void deleteResource(Object txId, Object resourceId,
166 boolean assureOnly) throws ResourceManagerException {
167
168 checkForVirtualAdminCommand(resourceId);
169
170 super.deleteResource(txId, resourceId, assureOnly);
171 }
172
173 public void createResource(Object txId, Object resourceId)
174 throws ResourceManagerException {
175
176 checkForVirtualAdminCommand(resourceId);
177
178 super.createResource(txId, resourceId);
179 }
180
181 public void createResource(Object txId, Object resourceId,
182 boolean assureOnly) throws ResourceManagerException {
183
184 checkForVirtualAdminCommand(resourceId);
185
186 super.createResource(txId, resourceId, assureOnly);
187 }
188
189 public void copyResource(Object txId, Object fromResourceId,
190 Object toResourceId, boolean overwrite)
191 throws ResourceManagerException {
192
193 checkForVirtualAdminCommand(fromResourceId);
194 checkForVirtualAdminCommand(toResourceId);
195
196 super.copyResource(txId, fromResourceId, toResourceId, overwrite);
197 }
198
199 public void moveResource(Object txId, Object fromResourceId,
200 Object toResourceId, boolean overwrite)
201 throws ResourceManagerException {
202
203 checkForVirtualAdminCommand(fromResourceId);
204 checkForVirtualAdminCommand(toResourceId);
205
206 super.moveResource(txId, fromResourceId, toResourceId, overwrite);
207 }
208
209 public InputStream readResource(Object resourceId)
210 throws ResourceManagerException {
211
212 if (isVirtualAdminId(resourceId)) {
213 logger.logWarning("Issuing virtual admin command" + resourceId);
214 return executeAdminCommand(resourceId);
215 }
216
217 return super.readResource(resourceId);
218 }
219
220 public InputStream readResource(Object txId, Object resourceId)
221 throws ResourceManagerException {
222
223 if (isVirtualAdminId(resourceId)) {
224 String message = "You must not call virtual admin commands ("
225 + resourceId + ") from within transactions!";
226 logger.logSevere(message);
227 throw new ResourceManagerException(message);
228 }
229
230 return super.readResource(txId, resourceId);
231 }
232
233 protected void checkForVirtualAdminCommand(Object resourceId)
234 throws ResourceManagerException {
235 if (isVirtualAdminId(resourceId)) {
236 String message = "You must not make modification calls to virtual admin commands ("
237 + resourceId + ")!";
238 logger.logSevere(message);
239 throw new ResourceManagerException(message);
240 }
241 }
242
243 protected boolean isVirtualAdminId(Object resourceId) {
244 return (getVirtualAdminPath() != null && resourceId.toString()
245 .startsWith(getVirtualAdminPath()));
246 }
247
248 protected InputStream executeAdminCommand(Object resourceId) {
249 StringBuffer sb = new StringBuffer();
250
251 if (!isVirtualAdminId(resourceId)) {
252 String message = "Internal error: " + resourceId.toString()
253 + " is no administration command, but is supposed to!";
254 sb.append(message);
255 logger.logSevere(message);
256 } else {
257 String command = resourceId.toString().substring(
258 getVirtualAdminPath().length());
259 logger.logInfo("Processing admin command " + command);
260
261 // XXX this really should be more flexible
262 try {
263 if (isAKnowCommand(command)) {
264 if (command.equals("recover")) {
265 recover();
266 }
267
268 String message = "Command " + command
269 + " terminated successfully";
270 sb.append(message);
271 logger.logInfo(message);
272 } else {
273 String message = "Command " + command + " unknown";
274 sb.append(message);
275 logger.logWarning(message);
276
277 }
278 } catch (ResourceManagerSystemException e) {
279 String message = "Command " + command
280 + " failed with the following message: "
281 + e.getMessage();
282 sb.append(message);
283 logger.logSevere(message, e);
284 }
285
286 }
287 ByteArrayInputStream baIs = new ByteArrayInputStream(sb.toString()
288 .getBytes());
289 return baIs;
290
291 }
292
293 protected boolean isAKnowCommand(String command) {
294 return command.equals("recover");
295 }
296
297 public OutputStream writeResource(Object txId, Object resourceId,
298 boolean append) throws ResourceManagerException {
299
300 checkForVirtualAdminCommand(resourceId);
301
302 return super.writeResource(txId, resourceId, append);
303 }
304 }