001 /* 002 Copyright (C) 2001-2003 Lionel Seinturier <Lionel.Seinturier@lip6.fr> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public License 015 along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 017 018 package org.objectweb.jac.aspects.distrans.persistence; 019 020 import org.objectweb.jac.aspects.distrans.JOTMHelper; 021 import org.objectweb.jac.core.AspectComponent; 022 023 import java.sql.SQLException; 024 import java.util.HashMap; 025 import java.util.Map; 026 027 import javax.transaction.TransactionManager; 028 029 import org.enhydra.jdbc.standard.StandardXADataSource; 030 031 /** 032 * Transaction-enabled persistence storage. 033 * An instance this AC is mandatory with DisTransAC. 034 * This class delegates most of the work (apart from data sources 035 * registering) to a technical implementation of the persistence API 036 * PersistenceItf. 037 * Current implementations of this API: SimpleDbPersistence. 038 * 039 * Relies on jac.aspects.distrans.JOTMHelper 040 * to retrieve the JOTM instance used by JAC. 041 * 042 * @author Lionel Seinturier <Lionel.Seinturier@lip6.fr> 043 * @version 1.0 044 */ 045 public class PersistenceAC extends AspectComponent { 046 047 public PersistenceAC() {} 048 049 /** A map storing data sources. */ 050 private Map sources = new HashMap(); 051 052 /** 053 * Define a data source name that will be later on used by the remaining 054 * configuration methods of this AC. 055 * 056 * @param sourceName the data source name 057 * @param driver the JDBC driver name (eg org.postgresql.Driver) 058 * @param url the JDBC URL (eg jdbc:postgresql://localhost/test) 059 * @param user the login to use 060 * @param password the password to use 061 */ 062 public void defineDataSource( 063 String sourceName, 064 String driver, String url, String user, String password ) { 065 066 StandardXADataSource xads = new StandardXADataSource(); 067 try { 068 xads.setDriverName(driver); 069 } catch (SQLException e) { 070 e.printStackTrace(); 071 System.exit(1); 072 } 073 xads.setUrl(url); 074 xads.setUser(user); 075 xads.setPassword(password); 076 TransactionManager tm = JOTMHelper.get().getTransactionManager(); 077 xads.setTransactionManager(tm); 078 079 sources.put( sourceName, xads ); 080 } 081 082 083 /** 084 * The instance implementing the technical API for persistence. 085 * SimpleDbPersistence implements it. 086 */ 087 private PersistenceItf storage; 088 089 public void setStorageType( String classname ) { 090 try { 091 _setStorageType(classname); 092 return; 093 } catch (ClassNotFoundException e) { 094 e.printStackTrace(); 095 } catch (InstantiationException e) { 096 e.printStackTrace(); 097 } catch (IllegalAccessException e) { 098 e.printStackTrace(); 099 } 100 System.exit(1); 101 } 102 103 private void _setStorageType( String classname ) 104 throws ClassNotFoundException, InstantiationException, IllegalAccessException { 105 106 Class storageClass = Class.forName(classname); 107 if (!PersistenceItf.class.isAssignableFrom(storageClass)) 108 throw new RuntimeException(classname+" must implement jac.aspects.distrans.persistence.PersistenceItf"); 109 110 storage = (PersistenceItf) storageClass.newInstance(); 111 } 112 113 114 /** 115 * Initialize the persistence storage. 116 * If the storage already exists, do not reinitialize it. 117 * 118 * @param className the class name for which we want to create a storage 119 * @param sourceName the data source name 120 */ 121 public void initStorageIfNeeded( String className, String sourceName ) { 122 123 if ( storage == null ) 124 throw new RuntimeException("setStorageType() must be called first"); 125 126 StandardXADataSource ds = (StandardXADataSource) sources.get(sourceName); 127 if ( ds == null ) 128 throw new RuntimeException("Unknown data source "+sourceName); 129 130 storage.initStorageIfNeeded(className,ds); 131 } 132 133 /** 134 * Initialize the persistence storage. 135 * If the storage already exists, reinitialize it. 136 * 137 * @param className the class name for which we want to create a storage 138 * @param sourceName the data source name 139 */ 140 public void initStorage( String className, String sourceName ) { 141 142 if ( storage == null ) 143 throw new RuntimeException("setStorageType() must be called first"); 144 145 StandardXADataSource ds = (StandardXADataSource) sources.get(sourceName); 146 if ( ds == null ) 147 throw new RuntimeException("Unknown data source "+sourceName); 148 149 storage.initStorage(className,ds); 150 } 151 152 /** 153 * All objects matching the objectNameExpression 154 * are made persistent to a SQL database represented by the data source. 155 * These objects are ressources that will potentially be used 156 * later on in transactions. 157 * 158 * Even if the objectNameExpression can be any regular expression, 159 * it is assumed to designate instances storable in existing 160 * storages (eventually call initStorageIfNeeded before). 161 * 162 * @param objectNameExpression the object name expression 163 * @param sourceName the source name 164 */ 165 public void registerPersistentRessource( 166 String objectNameExpression, String sourceName ) { 167 168 if ( storage == null ) 169 throw new RuntimeException("setStorageType() must be called first"); 170 171 StandardXADataSource ds = (StandardXADataSource) sources.get(sourceName); 172 if ( ds == null ) 173 throw new RuntimeException("Unknown data source "+sourceName); 174 175 /** 176 * Wrap methods that perform write operations. 177 * Modifier methods in all the classes 178 * for all the objects matching objectNameExpression. 179 */ 180 WriteWrapper pw = new WriteWrapper(this,storage,ds); 181 pointcut( 182 objectNameExpression, "ALL", "MODIFIERS", 183 pw, null 184 ); 185 186 /** 187 * Wrap methods that perform read operations. 188 * Accessor and modifier methods in all the classes 189 * for all the objects matching objectNameExpression. 190 * Note: modifiers read fields before modifying them. 191 */ 192 ReadWrapper rw = new ReadWrapper(this,storage,ds); 193 pointcut( 194 objectNameExpression, "ALL", "MODIFIERS || ACCESSORS", 195 rw, null 196 ); 197 } 198 199 }