001: /*
002: * argun 1.0
003: * Web 2.0 delivery framework
004: * Copyright (C) 2007 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.web.analysis;
024:
025: import gnu.trove.TIntObjectHashMap;
026:
027: import java.sql.Connection;
028: import java.sql.SQLException;
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.HashSet;
032: import java.util.Iterator;
033: import java.util.Map;
034: import java.util.Set;
035: import java.util.TreeMap;
036:
037: import biz.hammurapi.sql.IdentityGenerator;
038: import biz.hammurapi.sql.IdentityManager;
039: import biz.hammurapi.sql.IdentityRetriever;
040: import biz.hammurapi.sql.SQLProcessor;
041: import biz.hammurapi.web.HammurapiWebRuntimeException;
042: import biz.hammurapi.web.analysis.sql.AnalysisEngine;
043: import biz.hammurapi.web.analysis.sql.AnalysisGlossaryLink;
044: import biz.hammurapi.web.analysis.sql.AnalysisTerm;
045: import biz.hammurapi.web.menu.Menu;
046:
047: public class AnalysisTermSource implements TermSource {
048:
049: private SQLProcessor processor;
050: private IdentityManager identityManager;
051: private boolean createTerms;
052: private AnalysisEngine engine;
053: private Set idSet;
054: private int glossaryId;
055: private boolean readOnlyView;
056:
057: public AnalysisTermSource(int glossaryId, SQLProcessor processor,
058: IdentityManager identityManager, boolean createTerms,
059: boolean readOnlyView, Set idSet) {
060: this .processor = processor;
061: this .engine = new AnalysisEngine(processor);
062: this .identityManager = identityManager;
063: this .createTerms = createTerms;
064: this .glossaryId = glossaryId;
065: this .readOnlyView = readOnlyView;
066: this .idSet = idSet;
067: }
068:
069: public AnalysisTermSource(int glossaryId, SQLProcessor processor,
070: IdentityManager identityManager, boolean createTerms,
071: boolean readOnlyView) {
072: this (glossaryId, processor, identityManager, createTerms,
073: readOnlyView, new HashSet());
074: }
075:
076: private Map termMap = new TreeMap();
077: private TIntObjectHashMap termIdMap = new TIntObjectHashMap();
078:
079: public Object getTerm(String namespace, String term, String text) {
080: if (Menu.isBlank(term)) {
081: return null;
082: }
083: if (Menu.isBlank(namespace)) {
084: namespace = "";
085: }
086: String key = Menu.isBlank(namespace) ? term : namespace + ":"
087: + term;
088: AnalysisTermEx ret = (AnalysisTermEx) termMap.get(key);
089: if (ret == null) {
090: ret = _getTerm(namespace, term, text);
091: termMap.put(key, ret);
092: if (ret != null) {
093: termIdMap.put(ret.getId(), ret);
094: }
095: }
096: if (ret != null) {
097: ret.incRef();
098: ret.setAlternativeText(text);
099: ret.setReadOnlyView(readOnlyView);
100: }
101: return ret;
102: }
103:
104: private AnalysisTermEx _getTerm(String namespace, String term,
105: String text) {
106: try {
107: int pidx = term.indexOf("(");
108: int didx = term.indexOf(".");
109: boolean validDot = didx > 0 && didx < term.length() - 1
110: && (pidx == -1 || didx < pidx - 1);
111: AnalysisTermEx parentTerm = null;
112: if (validDot) {
113: String pName = term.substring(0, didx);
114: String parentKey = Menu.isBlank(namespace) ? pName
115: : namespace + ":" + pName;
116: parentTerm = (AnalysisTermEx) termMap.get(parentKey);
117: if (parentTerm == null) {
118: parentTerm = _getTerm(namespace, pName, null);
119: if (parentTerm != null) {
120: termMap.put(parentKey, parentTerm);
121: termIdMap.put(parentTerm.getId(), parentTerm);
122: }
123: }
124: term = term.substring(didx + 1);
125: }
126:
127: AnalysisTermEx ret;
128:
129: // Check masters first
130: if (idSet == null) {
131: idSet = new HashSet();
132: }
133: Iterator it = engine.getAnalysisGlossaryLinkBySlave(
134: glossaryId, new ArrayList()).iterator();
135: while (it.hasNext()) {
136: AnalysisGlossaryLink link = (AnalysisGlossaryLink) it
137: .next();
138: if (Menu.isBlank(link.getNamespace())) { // Pass as is.
139: Integer key = new Integer(link.getMaster());
140: try {
141: if (idSet.add(key)) {
142: AnalysisTermSource linked = new AnalysisTermSource(
143: link.getMaster(), processor,
144: identityManager, false, //If namespace is null then don't create terms in the master
145: readOnlyView, idSet);
146: ret = linked
147: ._getTerm(namespace, term, text);
148: if (ret != null) {
149: return ret;
150: }
151: }
152: } finally {
153: idSet.remove(key);
154: }
155: } else {
156: String key = link.getNamespace() + ":"
157: + link.getMaster();
158: try {
159: if (!Menu.isBlank(namespace) && idSet.add(key)) {
160: AnalysisTermSource linked = new AnalysisTermSource(
161: link.getMaster(), processor,
162: identityManager, createTerms,
163: readOnlyView, idSet);
164: if (namespace.equals(link.getNamespace())) {
165: ret = linked._getTerm("", term, text);
166: if (ret != null) {
167: return ret;
168: }
169: } else if (namespace.startsWith(link
170: .getNamespace()
171: + "/")) {
172: String subNamespace = namespace
173: .substring(link.getNamespace()
174: .length() + 1);
175: ret = linked._getTerm(subNamespace,
176: term, text);
177: if (ret != null) {
178: return ret;
179: }
180: }
181: }
182: } finally {
183: idSet.remove(key);
184: }
185: }
186: }
187:
188: // Search in self
189: if (parentTerm == null) {
190: ret = (AnalysisTermEx) engine.getRootTermByName(
191: glossaryId, namespace, term,
192: AnalysisTermEx.class);
193: } else {
194: ret = (AnalysisTermEx) engine.getChildTermByName(
195: parentTerm.getId(), term, AnalysisTermEx.class);
196: }
197:
198: if (ret != null) {
199: if (ret.getParentId() != null) {
200: parentTerm = (AnalysisTermEx) termIdMap.get(ret
201: .getParentId().intValue());
202: if (parentTerm == null) {
203: parentTerm = (AnalysisTermEx) engine
204: .getAnalysisTerm(ret.getParentId()
205: .intValue(),
206: AnalysisTermEx.class);
207: addTerm(parentTerm);
208: }
209: ret.setParent(parentTerm);
210: }
211: return ret;
212: }
213:
214: if (createTerms) {
215: Connection con = processor.getConnection();
216: AnalysisTermEx newTerm = new AnalysisTermEx(true);
217: newTerm.setParent(parentTerm);
218: AnalysisEngine engine = new AnalysisEngine(
219: new SQLProcessor(con, null));
220: newTerm.setGlossaryId(new Integer(glossaryId));
221: newTerm.setIsAutocreated(true);
222: if (validDot) {
223: if (pidx > 0
224: && term.charAt(term.length() - 1) == ')') {
225: newTerm.setCategory("Operation");
226: } else {
227: newTerm.setCategory("Attribute");
228: }
229: } else {
230: newTerm.setCategory("Class");
231: }
232: newTerm.setName(term);
233: newTerm.setNamespace(namespace);
234: if (identityManager instanceof IdentityGenerator) {
235: newTerm.setId(((IdentityGenerator) identityManager)
236: .generate(con, "INTERACTION"));
237: }
238: engine.insertAnalysisTerm(newTerm);
239: if (identityManager instanceof IdentityRetriever) {
240: newTerm.setId(((IdentityRetriever) identityManager)
241: .retrieve(con));
242: }
243:
244: processor.releaseConnection(con);
245:
246: return newTerm;
247: }
248:
249: return null;
250: } catch (SQLException e) {
251: throw new HammurapiWebRuntimeException(
252: "Could not find term: " + e, e);
253: }
254: }
255:
256: /**
257: * Adds term to term cache.
258: * @param term
259: */
260: public void addTerm(AnalysisTermEx term) {
261: String key = Menu.isBlank(term.getNamespace()) ? term.getName()
262: : term.getNamespace() + ":" + term.getName();
263: termMap.put(key, term);
264: termIdMap.put(term.getId(), term);
265: addTerms(term.getChildren());
266: }
267:
268: /**
269: * Adds collection of terms to term cache.
270: * @param terms
271: */
272: public void addTerms(Collection terms) {
273: Iterator it = terms.iterator();
274: while (it.hasNext()) {
275: addTerm((AnalysisTermEx) it.next());
276: }
277: }
278:
279: /**
280: * Pre-loads root terms from the database for given glossary
281: *
282: */
283: public void loadTerms() {
284: addTerms(engine.getRootTerms(glossaryId, AnalysisTermEx.class));
285: }
286:
287: public Collection getTerms() {
288: return termMap.values();
289: }
290:
291: /**
292: * @return Root terms grouped by namespaces and then by category and then by first letter
293: */
294: public Map getGroupedRootTerms() {
295: Map namespaceMap = new TreeMap();
296: Iterator it = getTerms().iterator();
297: while (it.hasNext()) {
298: AnalysisTerm term = (AnalysisTerm) it.next();
299: if (term != null && term.getParentId() == null
300: && term.getGlossaryId() != null
301: && term.getGlossaryId().intValue() == glossaryId) {
302: Map categoryMap = (Map) namespaceMap.get(term
303: .getNamespace());
304: if (categoryMap == null) {
305: categoryMap = new TreeMap();
306: namespaceMap.put(term.getNamespace(), categoryMap);
307: }
308: Map letterMap = (Map) categoryMap.get(term
309: .getCategory());
310: if (letterMap == null) {
311: letterMap = new TreeMap();
312: categoryMap.put(term.getCategory(), letterMap);
313: }
314:
315: String firstLetter = term.getName().substring(0, 1)
316: .toUpperCase();
317: if ("&".equals(firstLetter)) {
318: int idx = term.getName().indexOf(";");
319: if (idx > 0) {
320: firstLetter = term.getName().substring(0,
321: idx + 1);
322: }
323: }
324: Collection terms = (Collection) letterMap
325: .get(firstLetter);
326: if (terms == null) {
327: terms = new ArrayList();
328: letterMap.put(firstLetter, terms);
329: }
330: terms.add(term);
331: }
332: }
333: return namespaceMap;
334: }
335:
336: }
|