001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.ejb.beans;
034:
035: import com.flexive.core.Database;
036: import static com.flexive.core.DatabaseConst.*;
037: import com.flexive.core.structure.StructureLoader;
038: import com.flexive.shared.CacheAdmin;
039: import com.flexive.shared.FxContext;
040: import com.flexive.shared.FxLanguage;
041: import com.flexive.shared.cache.FxCacheException;
042: import com.flexive.shared.content.FxPermissionUtils;
043: import com.flexive.shared.exceptions.*;
044: import com.flexive.shared.interfaces.LanguageEngine;
045: import com.flexive.shared.interfaces.LanguageEngineLocal;
046: import com.flexive.shared.mbeans.FxCacheMBean;
047: import com.flexive.shared.security.Role;
048: import com.flexive.shared.value.FxString;
049: import org.apache.commons.logging.Log;
050: import org.apache.commons.logging.LogFactory;
051:
052: import javax.ejb.*;
053: import java.sql.*;
054: import java.util.ArrayList;
055: import java.util.HashMap;
056: import java.util.List;
057: import java.util.Map;
058:
059: /**
060: * [fleXive] language engine interface.
061: * This engine should not be used to load languages as they are available from the environment!
062: * Its purpose is to enable/disable, initially load and manage (position, etc.) languages.
063: *
064: * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
065: * @version $Rev
066: */
067:
068: @Stateless(name="LanguageEngine")
069: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
070: @TransactionManagement(TransactionManagementType.CONTAINER)
071: public class LanguageBean implements LanguageEngine,
072: LanguageEngineLocal {
073:
074: private static transient Log LOG = LogFactory
075: .getLog(LanguageBean.class);
076:
077: /**
078: * All tables that have references to languages and the referencing column
079: */
080: private final static String[][] LANG_USAGE = {
081: { TBL_ACCOUNTS, "LANG" }, { TBL_ACLS + ML, "LANG" },
082: { TBL_STEPDEFINITION + ML, "LANG" },
083: { TBL_STRUCT_TYPES + ML, "LANG" },
084: { TBL_STRUCT_GROUPS + ML, "LANG" },
085: { TBL_STRUCT_DATATYPES + ML, "LANG" },
086: { TBL_SELECTLIST + ML, "LANG" },
087: { TBL_SELECTLIST_ITEM + ML, "LANG" },
088: { TBL_STRUCT_PROPERTIES + ML, "LANG" },
089: { TBL_STRUCT_ASSIGNMENTS, "DEFLANG" },
090: { TBL_STRUCT_ASSIGNMENTS + ML, "LANG" },
091: { TBL_CONTENT, "MAINLANG" }, { TBL_CONTENT_DATA, "LANG" },
092: { TBL_CONTENT_DATA_FT, "LANG" } };
093:
094: /**
095: * {@inheritDoc} *
096: */
097: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
098: public FxLanguage load(long languageId)
099: throws FxApplicationException {
100: try {
101: FxLanguage lang = (FxLanguage) CacheAdmin.getInstance()
102: .get(CacheAdmin.LANGUAGES_ID, languageId);
103: if (lang == null) {
104: loadAll(true, true);
105: lang = (FxLanguage) CacheAdmin.getInstance().get(
106: CacheAdmin.LANGUAGES_ID, languageId);
107: if (lang == null)
108: throw new FxInvalidLanguageException(
109: "ex.language.invalid", languageId);
110: }
111: return lang;
112: } catch (FxCacheException e) {
113: throw new FxLoadException(LOG, e);
114: }
115: }
116:
117: /**
118: * {@inheritDoc} *
119: */
120: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
121: public FxLanguage load(String languageIsoCode)
122: throws FxApplicationException {
123: try {
124: FxLanguage lang = (FxLanguage) CacheAdmin.getInstance()
125: .get(CacheAdmin.LANGUAGES_ISO, languageIsoCode);
126: if (lang == null) {
127: loadAll(true, true);
128: lang = (FxLanguage) CacheAdmin.getInstance().get(
129: CacheAdmin.LANGUAGES_ISO, languageIsoCode);
130: if (lang == null)
131: throw new FxInvalidLanguageException(
132: "ex.language.invalid", languageIsoCode);
133: }
134: return lang;
135: } catch (FxCacheException e) {
136: throw new FxLoadException(LOG, e);
137: }
138: }
139:
140: /**
141: * {@inheritDoc}
142: */
143: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
144: public FxLanguage[] loadAvailable() throws FxApplicationException {
145: try {
146: FxLanguage[] available = (FxLanguage[]) CacheAdmin
147: .getInstance().get(CacheAdmin.LANGUAGES_ALL, "id");
148: if (available == null) {
149: loadAll(true, true);
150: available = (FxLanguage[]) CacheAdmin.getInstance()
151: .get(CacheAdmin.LANGUAGES_ALL, "id");
152: if (available == null)
153: throw new FxInvalidLanguageException(
154: "ex.language.loadFailed");
155: }
156: return available;
157: } catch (FxCacheException e) {
158: throw new FxLoadException(LOG, e);
159: }
160: }
161:
162: /**
163: * {@inheritDoc} *
164: */
165: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
166: public List<FxLanguage> loadDisabled()
167: throws FxApplicationException {
168: return loadAll(false, false);
169: }
170:
171: /**
172: * {@inheritDoc} *
173: */
174: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
175: public List<FxLanguage> loadAvailable(boolean excludeSystemLanguage)
176: throws FxApplicationException {
177: FxLanguage[] tmp = loadAvailable();
178: ArrayList<FxLanguage> result = new ArrayList<FxLanguage>();
179: for (FxLanguage lang : tmp) {
180: if (excludeSystemLanguage && lang.getId() == 0)
181: continue;
182: result.add(lang);
183: }
184: return result;
185: }
186:
187: /**
188: * {@inheritDoc} *
189: */
190: @TransactionAttribute(TransactionAttributeType.SUPPORTS)
191: public boolean isValid(long languageId) {
192: // Does the language exist at all? Check via constru
193: try {
194: load(languageId);
195: } catch (FxApplicationException exc) {
196: return false;
197: }
198: return true;
199: }
200:
201: /**
202: * Initial load function.
203: *
204: * @param used load used or unused languages?
205: * @param add2cache put loaded languages into cache?
206: * @return list containing requested languages
207: */
208: private synchronized List<FxLanguage> loadAll(boolean used,
209: boolean add2cache) {
210: String sql = "SELECT l.LANG_CODE, l.ISO_CODE, t.LANG, t.DESCRIPTION FROM "
211: + TBL_LANG
212: + " l, "
213: + TBL_LANG
214: + ML
215: + " t "
216: + "WHERE t.LANG_CODE=l.LANG_CODE AND l.INUSE="
217: + used
218: + " ORDER BY l.DISPPOS ASC, l.LANG_CODE ASC";
219: Connection con = null;
220: Statement stmt = null;
221: List<FxLanguage> alLang = new ArrayList<FxLanguage>(140);
222: try {
223: con = Database.getDbConnection();
224: stmt = con.createStatement();
225: ResultSet rs = stmt.executeQuery(sql);
226: Map<Long, String> hmMl = new HashMap<Long, String>(5);
227: int lang_code = -1;
228: String iso_code = null;
229: FxCacheMBean cache = CacheAdmin.getInstance();
230: while (rs != null && rs.next()) {
231: if (lang_code != rs.getInt(1)) {
232: if (lang_code != -1
233: && lang_code != FxLanguage.SYSTEM_ID) {
234: //add
235: FxLanguage lang = new FxLanguage(lang_code,
236: iso_code, new FxString(
237: FxLanguage.DEFAULT_ID, hmMl),
238: true);
239: if (add2cache) {
240: cache.put(CacheAdmin.LANGUAGES_ID, lang
241: .getId(), lang);
242: cache.put(CacheAdmin.LANGUAGES_ISO, lang
243: .getIso2digit(), lang);
244: }
245: alLang.add(lang);
246: }
247: lang_code = rs.getInt(1);
248: iso_code = rs.getString(2);
249: hmMl.clear();
250: }
251: hmMl.put(rs.getLong(3), rs.getString(4));
252: }
253: if (lang_code != -1 && lang_code != FxLanguage.SYSTEM_ID) {
254: //add
255: FxLanguage lang = new FxLanguage(lang_code, iso_code,
256: new FxString(FxLanguage.DEFAULT_ID, hmMl), true);
257: if (add2cache) {
258: cache.put(CacheAdmin.LANGUAGES_ID, lang.getId(),
259: lang);
260: cache.put(CacheAdmin.LANGUAGES_ISO, lang
261: .getIso2digit(), lang);
262: }
263: alLang.add(lang);
264: }
265: if (add2cache)
266: cache.put(CacheAdmin.LANGUAGES_ALL, "id", alLang
267: .toArray(new FxLanguage[alLang.size()]));
268: } catch (SQLException e) {
269: LOG.error(e, e);
270: } catch (FxCacheException e) {
271: LOG.error(e, e);
272: } finally {
273: if (con != null)
274: Database.closeObjects(LanguageBean.class, con, stmt);
275: }
276: return alLang;
277: }
278:
279: /**
280: * {@inheritDoc}
281: */
282: @TransactionAttribute(TransactionAttributeType.REQUIRED)
283: public void setAvailable(List<FxLanguage> available,
284: boolean ignoreUsage) throws FxApplicationException {
285: FxPermissionUtils.checkRole(FxContext.get().getTicket(),
286: Role.GlobalSupervisor);
287: Connection con = null;
288: PreparedStatement ps = null;
289: if (available == null || available.size() == 0)
290: throw new FxInvalidParameterException("available",
291: "ex.language.noAvailable");
292: try {
293: con = Database.getDbConnection();
294: if (!ignoreUsage) {
295: List<FxLanguage> orgLang = loadAvailable(true);
296: boolean found;
297: for (FxLanguage org : orgLang) {
298: found = false;
299: for (FxLanguage tmp : available) {
300: if (tmp.getId() == org.getId()) {
301: found = true;
302: break;
303: }
304: }
305: if (!found && hasUsages(con, org))
306: throw new FxInvalidParameterException(
307: "available", "ex.language.removeUsed",
308: org.getLabel());
309: }
310: }
311: ps = con.prepareStatement("UPDATE " + TBL_LANG
312: + " SET INUSE=?, DISPPOS=?");
313: ps.setBoolean(1, false);
314: ps.setNull(2, java.sql.Types.INTEGER);
315: ps.executeUpdate();
316: ps.close();
317: int pos = 0;
318: ps = con.prepareStatement("UPDATE " + TBL_LANG
319: + " SET INUSE=?, DISPPOS=? WHERE LANG_CODE=?");
320: ps.setBoolean(1, true);
321: for (FxLanguage lang : available) {
322: ps.setInt(2, pos++);
323: ps.setLong(3, lang.getId());
324: ps.addBatch();
325: }
326: ps.executeBatch();
327: FxCacheMBean cache = CacheAdmin.getInstance();
328: cache.remove(CacheAdmin.LANGUAGES_ID);
329: cache.remove(CacheAdmin.LANGUAGES_ISO);
330: cache.remove(CacheAdmin.LANGUAGES_ALL);
331: StructureLoader.reload(con);
332: } catch (SQLException e) {
333: throw new FxUpdateException(LOG, e, "ex.db.sqlError", e
334: .getMessage());
335: } catch (FxCacheException e) {
336: throw new FxApplicationException(LOG, e);
337: } finally {
338: if (con != null)
339: Database.closeObjects(LanguageBean.class, con, ps);
340: }
341: }
342:
343: /**
344: * Check if the given language is referenced from a table
345: *
346: * @param con an open and valid connection
347: * @param language the language to check
348: * @return if the language is in use
349: * @throws FxApplicationException on errors
350: * @throws SQLException on errors
351: */
352: private boolean hasUsages(Connection con, FxLanguage language)
353: throws FxApplicationException, SQLException {
354: System.out.println("checking removed language "
355: + language.getLabel().getBestTranslation());
356: PreparedStatement ps = null;
357: try {
358: ResultSet rs;
359: for (String[] check : LANG_USAGE) {
360: if (ps != null)
361: ps.close();
362: ps = con.prepareStatement("SELECT COUNT(*) FROM "
363: + check[0] + " WHERE " + check[1] + "=?");
364: ps.setLong(1, language.getId());
365: rs = ps.executeQuery();
366: if (rs != null && rs.next()) {
367: if (rs.getLong(1) > 0) {
368: LOG.info("Language [" + language.getIso2digit()
369: + "] has [" + rs.getLong(1)
370: + "] usages in table " + check[0]
371: + ", column " + check[1]);
372: return true;
373: }
374: }
375: }
376: } finally {
377: if (ps != null)
378: ps.close();
379: }
380: return false;
381: }
382: }
|