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 */ 017package org.apache.commons.transaction.file; 018 019import java.io.ByteArrayInputStream; 020import java.io.InputStream; 021import java.io.OutputStream; 022 023import 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 */ 032public 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}