View Javadoc

1   /*
2    * The SmartWeb Framework
3    * Copyright (C) 2004-2006
4    *
5    * This library is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2.1 of the License, or (at your option) any later version.
9    *
10   * This library is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   * Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public
16   * License along with this library; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18   *
19   * For further informations on the SmartWeb Framework please visit
20   *
21   *                        http://smartweb.sourceforge.net
22   */
23  package net.smartlab.web;
24  
25  import java.net.URL;
26  
27  import net.smartlab.config.Configuration;
28  import net.smartlab.config.ConfigurationException;
29  import net.smartlab.web.config.DomainConfigurationStrategy;
30  import net.smartlab.web.config.FileDomainConfigurationStrategy;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.hibernate.HibernateException;
35  import org.hibernate.StaleObjectStateException;
36  import org.hibernate.Transaction;
37  
38  /**
39   * @author   rlogiacco
40   * @uml.dependency   supplier="net.smartlab.web.config.DomainConfigurationStrategy"
41   * @uml.dependency   supplier="net.smartlab.web.BusinessException"
42   * @uml.dependency   supplier="net.smartlab.web.BusinessObjectFactory"
43   */
44  public abstract class Domain implements ManageableDomain {
45  
46  	/**
47  	 * Provides the execution context through which additional informations can
48  	 * be transparently transmitted in a multiple tier architecture.
49  	 */
50  	final static ThreadLocal context = new ThreadLocal();
51  
52  	/**
53  	 * Provides logging capabilities to the domain.
54  	 */
55  	protected final Log logger = LogFactory.getLog(this.getClass());
56  
57  	/**
58  	 * The internal configuration.
59  	 */
60  	private Configuration config;
61  
62  	/**
63  	 * Strategy to retrieve the configuration file.
64  	 */
65  	private static DomainConfigurationStrategy strategy = new FileDomainConfigurationStrategy();
66  	static {
67  		try {
68  			String strategy = System.getProperty("smartweb.domain.strategy");
69  			if (strategy != null) {
70  				Domain.strategy = (DomainConfigurationStrategy)Class.forName(strategy).newInstance();
71  			} else {
72  				LogFactory.getLog(Domain.class).warn("No configuration found: falling back to default configuration");
73  			}
74  		} catch (Exception e) {
75  			LogFactory.getLog(Domain.class).fatal("Error configuring SmartWeb", e);
76  		}
77  	}
78  
79  
80  	/**
81  	 * Starts a new transaction, allowing all the operations performed in the
82  	 * same context to be atomically applied (commit) or reverted (rollback).
83  	 * The context is identifyied by a <code>BusinessObjectFactory</code>
84  	 * instance but the context spans over all the instances sharing the same
85  	 * configuration.
86  	 * 
87  	 * @param factory the identifier for the context
88  	 * @return an object representation of the transaction.
89  	 * @throws BusinessException if something wrong occurs during the operation.
90  	 */
91  	protected Transaction begin(BusinessObjectFactory factory) throws BusinessException {
92  		try {
93  			return factory.current().beginTransaction();
94  		} catch (HibernateException he) {
95  			logger.error("[ smartweb ] failed to begin transaction");
96  			throw new BusinessException("persistence.error.begin", he);
97  		} catch (DAOException boe) {
98  			throw new BusinessException(boe);
99  		}
100 	}
101 
102 	/**
103 	 * Commits the specified transaction applying all the changes happened since
104 	 * its beginning.
105 	 * 
106 	 * @param transaction the transaction to commit.
107 	 * @throws BusinessException if something wrong occurs during the operation.
108 	 */
109 	protected void commit(Transaction transaction) throws BusinessException {
110 		try {
111 			transaction.commit();
112 		} catch (StaleObjectStateException sose) {
113 			logger.info("[ smartweb ] optimistical locking collision");
114 			throw new BusinessException("persistence.locking.collision", sose);
115 		} catch (HibernateException he) {
116 			logger.error("[ smartweb ] failed to commit transaction");
117 			throw new BusinessException("persistence.error.commit", he);
118 		}
119 	}
120 
121 	/**
122 	 * Rollbacks the specified transaction reverting all the changes happened
123 	 * since its beginning.
124 	 * 
125 	 * @param transaction the transaction to rollback.
126 	 * @throws BusinessException if something wrong occurs during the operation.
127 	 */
128 	protected void rollback(Transaction transaction) throws BusinessException {
129 		try {
130 			transaction.rollback();
131 		} catch (HibernateException he) {
132 			logger.warn("[ smartweb ] failed to rollback transaction");
133 		}
134 	}
135 
136 	/**
137 	 * Changes the strategy used to configure the domain.
138 	 * 
139 	 * @param strategy an implementation of the
140 	 *        <code>DomainConfigurationStrategy</code> interface.
141 	 */
142 	public static void setConfigurationStrategy(DomainConfigurationStrategy strategy) {
143 		Domain.strategy = strategy;
144 	}
145 
146 	/**
147 	 * Subclasses should make their own constructors private and behave like
148 	 * singletons.
149 	 */
150 	protected Domain() {
151 		if (logger.isDebugEnabled()) {
152 			logger.debug(this.getClass().getName() + " instantiated.");
153 		}
154 	}
155 
156 	/**
157 	 * Returns the <code>Configuration</code> instance used by this instance.
158 	 * 
159 	 * @return the <code>Configuration</code> instance used by this instance.
160 	 * @throws ConfigurationException if something wrong occurs while reading
161 	 *         the configuration file, usually meaning the configuration file is
162 	 *         missing.
163 	 */
164 	public Configuration getConfiguration() throws ConfigurationException {
165 		if (config == null) {
166 			this.config = strategy.getConfiguration(this);
167 		}
168 		return config;
169 	}
170 
171 	/**
172 	 * Returns the <code>Configuration</code> instance used by this instance.
173 	 * 
174 	 * @param filename the configuration file name.
175 	 * @return the <code>Configuration</code> instance used by this instance.
176 	 * @throws ConfigurationException if something wrong occurs while reading
177 	 *         the configuration file, usually meaning the configuration file is
178 	 *         missing.
179 	 */
180 	public Configuration getConfiguration(String filename) throws ConfigurationException {
181 		if (config == null) {
182 			config = strategy.getConfiguration(this, filename);
183 		}
184 		return config;
185 	}
186 
187 	/**
188 	 * Returns the first resource in the list available in the specified
189 	 * context.
190 	 * 
191 	 * @param context the class identifying the search context.
192 	 * @param names the list, ordered from first to last, of resources to search
193 	 *        for.
194 	 * @return the first resource in the list available in the context.
195 	 */
196 	public static URL getResource(Class context, String[] names) {
197 		Log logger = LogFactory.getLog(context);
198 		URL resource = null;
199 		for (int i = 0; i < names.length; i++) {
200 			resource = context.getResource(names[i]);
201 			logger.trace("   trying `" + names[i] + "`");
202 			if (resource != null) {
203 				break;
204 			}
205 		}
206 		logger.debug("   resource is `" + resource + "`");
207 		if (resource == null) {
208 			logger.warn("No resource found in " + names);
209 		}
210 		return resource;
211 	}
212 
213 	/**
214 	 * Returns the name of the last archive containing the class or an
215 	 * <code>empty</code> string if the class is in no archive.
216 	 * 
217 	 * @param type the class to search for.
218 	 * @return the name of the last archive containing the class or an
219 	 *         <code>empty</code> string if the class is in no archive.
220 	 */
221 	public static String getLastArchiveName(Class type) {
222 		Log logger = LogFactory.getLog(type);
223 		String path = type.getProtectionDomain().getCodeSource().getLocation().getFile();
224 		if (path.indexOf("/WEB-INF/classes") > -1) {
225 			// non jar packaged deploy, we are packaged as war classes
226 			path.substring(0, path.indexOf("/WEB-INF/classes"));
227 		}
228 		logger.debug("   archive path is `" + path + "`");
229 		return path.substring(path.lastIndexOf('/') + 1);
230 	}
231 }