1 22 package org.jboss.ejb.plugins; 23 24 import java.io.File ; 25 import java.io.InputStream ; 26 import java.io.OutputStream ; 27 import java.io.ObjectInputStream ; 28 import java.io.ObjectOutputStream ; 29 import java.io.FileOutputStream ; 30 import java.io.FileInputStream ; 31 import java.io.BufferedOutputStream ; 32 import java.io.BufferedInputStream ; 33 import java.io.IOException ; 34 35 import java.lang.reflect.Method ; 36 import java.lang.reflect.Field ; 37 38 import java.util.ArrayList ; 39 import java.util.Collection ; 40 import java.util.Collections ; 41 import java.util.Iterator ; 42 43 import javax.ejb.EJBObject ; 44 import javax.ejb.Handle ; 45 import javax.ejb.CreateException ; 46 import javax.ejb.DuplicateKeyException ; 47 import javax.ejb.EJBException ; 48 import javax.ejb.FinderException ; 49 import javax.ejb.RemoveException ; 50 51 import org.jboss.ejb.Container; 52 import org.jboss.ejb.EntityContainer; 53 import org.jboss.ejb.EntityPersistenceStore; 54 import org.jboss.ejb.EntityEnterpriseContext; 55 import org.jboss.ejb.GenericEntityObjectFactory; 56 import org.jboss.metadata.EntityMetaData; 57 58 import org.jboss.system.server.ServerConfigLocator; 59 import org.jboss.system.ServiceMBeanSupport; 60 61 import org.jboss.util.file.FilenameSuffixFilter; 62 63 100 public class CMPFilePersistenceManager 101 extends ServiceMBeanSupport 102 implements EntityPersistenceStore 103 { 104 105 public static final String DEFAULT_STORE_DIRECTORY_NAME = "entities"; 106 107 108 private EntityContainer con; 109 110 116 private String storeDirName = DEFAULT_STORE_DIRECTORY_NAME; 117 118 119 private File storeDir; 120 121 122 private Field idField; 123 124 125 private Method isModified; 126 127 133 public void setContainer(final Container c) 134 { 135 con = (EntityContainer)c; 136 } 137 138 143 159 public void setStoreDirectoryName(final String dirName) 160 { 161 this.storeDirName = dirName; 162 } 163 164 174 public String getStoreDirectoryName() 175 { 176 return storeDirName; 177 } 178 179 186 public File getStoreDirectory() 187 { 188 return storeDir; 189 } 190 191 protected void createService() throws Exception 192 { 193 195 String ejbName = con.getBeanMetaData().getEjbName(); 196 197 File dir = ServerConfigLocator.locate().getServerDataDir(); 199 200 206 dir = new File (dir, storeDirName); 208 dir = new File (dir, ejbName); 209 storeDir = dir; 210 211 log.debug("Storing entity state for '" + ejbName + "' in: " + storeDir); 212 213 if (!storeDir.exists()) { 215 if (!storeDir.mkdirs()) { 216 throw new IOException ("Failed to create directory: " + storeDir); 217 } 218 } 219 220 if (!storeDir.isDirectory()) { 222 throw new IOException ("File exists where directory expected: " + storeDir); 223 } 224 225 if (!storeDir.canWrite() || !storeDir.canRead()) { 227 throw new IOException ("Directory must be readable and writable: " + storeDir); 228 } 229 230 idField = con.getBeanClass().getField("id"); 232 log.debug("Using id field: " + idField); 233 234 try 236 { 237 isModified = con.getBeanClass().getMethod("isModified", new Class [0]); 238 if (!isModified.getReturnType().equals(Boolean.TYPE)) { 239 isModified = null; log.warn("Found isModified method, but return type is not boolean; ignoring"); 241 } 242 else { 243 log.debug("Using isModified method: " + isModified); 244 } 245 } 246 catch (NoSuchMethodException ignored) {} 247 } 248 249 252 protected void destroyService() throws Exception 253 { 254 storeDir.delete(); 255 } 256 257 public Object createBeanClassInstance() throws Exception 258 { 259 return con.getBeanClass().newInstance(); 260 } 261 262 273 public void initEntity(final EntityEnterpriseContext ctx) 274 { 275 Object instance = ctx.getInstance(); 277 Class ejbClass = instance.getClass(); 278 Field cmpField; 279 Class cmpFieldType; 280 281 EntityMetaData metaData = (EntityMetaData)con.getBeanMetaData(); 282 Iterator i = metaData.getCMPFields(); 283 284 while (i.hasNext()) 285 { 286 try 288 { 289 cmpField = ejbClass.getField((String )i.next()); 290 cmpFieldType = cmpField.getType(); 291 if (cmpFieldType.equals(boolean.class)) 294 { 295 cmpField.setBoolean(instance,false); 296 } 297 else if (cmpFieldType.equals(byte.class)) 298 { 299 cmpField.setByte(instance,(byte)0); 300 } 301 else if (cmpFieldType.equals(int.class)) 302 { 303 cmpField.setInt(instance,0); 304 } 305 else if (cmpFieldType.equals(long.class)) 306 { 307 cmpField.setLong(instance,0L); 308 } 309 else if (cmpFieldType.equals(short.class)) 310 { 311 cmpField.setShort(instance,(short)0); 312 } 313 else if (cmpFieldType.equals(char.class)) 314 { 315 cmpField.setChar(instance,'\u0000'); 316 } 317 else if (cmpFieldType.equals(double.class)) 318 { 319 cmpField.setDouble(instance,0d); 320 } 321 else if (cmpFieldType.equals(float.class)) 322 { 323 cmpField.setFloat(instance,0f); 324 } 325 else 326 { 327 cmpField.set(instance,null); 328 } 329 } 330 catch (NoSuchFieldException e) 331 { 332 } 335 catch (Exception e) 336 { 337 throw new EJBException (e); 338 } 339 } 340 } 341 342 public Object createEntity(final Method m, 343 final Object [] args, 344 final EntityEnterpriseContext ctx) 345 throws Exception 346 { 347 try { 348 Object id = idField.get(ctx.getInstance()); 349 350 if (getFile(id).exists()) 352 throw new DuplicateKeyException ("Already exists: "+id); 353 354 storeEntity(id, ctx.getInstance()); 356 357 return id; 358 } 359 catch (IllegalAccessException e) 360 { 361 throw new CreateException ("Could not create entity: "+e); 362 } 363 } 364 365 public Object postCreateEntity(final Method m, 366 final Object [] args, 367 final EntityEnterpriseContext ctx) 368 throws Exception 369 { 370 return null; 371 } 372 373 public Object findEntity(final Method finderMethod, 374 final Object [] args, 375 final EntityEnterpriseContext ctx, 376 GenericEntityObjectFactory factory) 377 throws FinderException 378 { 379 if (finderMethod.getName().equals("findByPrimaryKey")) 380 { 381 if (!getFile(args[0]).exists()) 382 throw new FinderException (args[0]+" does not exist"); 383 384 return factory.getEntityEJBObject(args[0]); 385 } 386 387 return null; 388 } 389 390 public Collection findEntities(final Method finderMethod, 391 final Object [] args, 392 final EntityEnterpriseContext ctx, 393 GenericEntityObjectFactory factory) 394 { 395 if (finderMethod.getName().equals("findAll")) 396 { 397 String [] files = storeDir.list(new FilenameSuffixFilter(".ser")); 398 ArrayList result = new ArrayList (files.length); 399 for (int i = 0; i < files.length; i++) { 400 final String key = files[i].substring(0,files[i].length()-4); 401 result.add(factory.getEntityEJBObject(key)); 402 } 403 404 return result; 405 } 406 else 407 { 408 return Collections.EMPTY_LIST; 410 } 411 } 412 413 416 public void activateEntity(final EntityEnterpriseContext ctx) 417 { 418 } 420 421 public void loadEntity(final EntityEnterpriseContext ctx) 422 { 423 try 424 { 425 Object obj = ctx.getInstance(); 426 427 ObjectInputStream in = new CMPObjectInputStream 429 (new BufferedInputStream (new FileInputStream (getFile(ctx.getId())))); 430 431 try { 432 Field [] f = obj.getClass().getFields(); 433 for (int i = 0; i < f.length; i++) 434 { 435 f[i].set(obj, in.readObject()); 436 } 437 } 438 finally { 439 in.close(); 440 } 441 } 442 catch (Exception e) 443 { 444 throw new EJBException ("Load failed", e); 445 } 446 } 447 448 private void storeEntity(Object id, Object obj) 449 { 450 try 451 { 452 ObjectOutputStream out = new CMPObjectOutputStream 454 (new BufferedOutputStream (new FileOutputStream (getFile(id)))); 455 456 try { 457 Field [] f = obj.getClass().getFields(); 458 for (int i = 0; i < f.length; i++) 459 { 460 out.writeObject(f[i].get(obj)); 461 } 462 } 463 finally { 464 out.close(); 465 } 466 } 467 catch (Exception e) 468 { 469 throw new EJBException ("Store failed", e); 470 } 471 } 472 473 public boolean isStoreRequired(final EntityEnterpriseContext ctx) throws Exception 474 { 475 if (isModified == null) 476 { 477 return true; 478 } 479 480 Boolean modified = (Boolean ) isModified.invoke(ctx.getInstance(), new Object [0]); 481 return modified.booleanValue(); 482 } 483 484 public boolean isModified(EntityEnterpriseContext ctx) throws Exception 485 { 486 return isStoreRequired(ctx); 487 } 488 489 public void storeEntity(final EntityEnterpriseContext ctx) 490 { 491 storeEntity(ctx.getId(), ctx.getInstance()); 492 } 493 494 497 public void passivateEntity(final EntityEnterpriseContext ctx) 498 { 499 } 501 502 public void removeEntity(final EntityEnterpriseContext ctx) 503 throws RemoveException 504 { 505 File file = getFile(ctx.getId()); 507 508 if (!file.delete()) { 509 throw new RemoveException ("Could not remove file: " + file); 510 } 511 } 512 513 protected File getFile(final Object id) 514 { 515 return new File (storeDir, String.valueOf(id) + ".ser"); 516 } 517 518 520 static class CMPObjectOutputStream 521 extends ObjectOutputStream 522 { 523 public CMPObjectOutputStream(final OutputStream out) 524 throws IOException 525 { 526 super(out); 527 enableReplaceObject(true); 528 } 529 530 protected Object replaceObject(final Object obj) 531 throws IOException 532 { 533 if (obj instanceof EJBObject ) 534 return ((EJBObject )obj).getHandle(); 535 536 return obj; 537 } 538 } 539 540 static class CMPObjectInputStream 541 extends ObjectInputStream 542 { 543 public CMPObjectInputStream(final InputStream in) 544 throws IOException 545 { 546 super(in); 547 enableResolveObject(true); 548 } 549 550 protected Object resolveObject(final Object obj) 551 throws IOException 552 { 553 if (obj instanceof Handle ) 554 return ((Handle )obj).getEJBObject(); 555 556 return obj; 557 } 558 } 559 } 560 561 | Popular Tags |