001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.module.corebuilders;
011:
012: import java.util.*;
013: import org.mmbase.cache.Cache;
014: import org.mmbase.module.core.*;
015: import org.mmbase.storage.search.*;
016: import org.mmbase.storage.search.implementation.*;
017:
018: import org.mmbase.util.logging.Logger;
019: import org.mmbase.util.logging.Logging;
020:
021: /**
022: * The OAlias builder is an optional corebuilder used to associate aliases with nodes.
023: * Each OAlias object contains a name field (the alias), and a destination field (the number of
024: * the object referenced).
025: * This builder is not used directly. If you add aliases, use {@link MMObjectBuilder#createAlias} instead
026: * of the builder's insert method.
027: * MMBase will run without this builder, but most applications use aliases.
028: *
029: * @author Rico Jansen
030: * @author Michiel Meeuwissen
031: * @version $Id: OAlias.java,v 1.23 2007/04/05 14:04:18 pierre Exp $
032: */
033:
034: public class OAlias extends MMObjectBuilder {
035:
036: private static final Logger log = Logging
037: .getLoggerInstance(OAlias.class);
038:
039: // alias -> node-number (Integer)
040: private Cache<String, Integer> numberCache = new Cache<String, Integer>(
041: 128) {
042: public String getName() {
043: return "AliasCache";
044: }
045:
046: public String getDescription() {
047: return "Cache for node aliases";
048: }
049: };
050:
051: private static final Integer NOT_FOUND = -1;
052:
053: public OAlias() {
054: numberCache.putCache();
055: }
056:
057: public boolean init() {
058: boolean res = super .init();
059: if (res)
060: checkAddTmpField("_destination");
061: return res;
062: }
063:
064: /**
065: * Obtain the number of a node through its alias
066: * @param name the alias of the desired node
067: * @return the number of the node, or -1 if the alias does not exist
068: * @see #getAliasedNode
069: */
070: public int getNumber(String name) {
071: if (log.isDebugEnabled()) {
072: log.debug("Finding oalias node '" + name + "'");
073: }
074:
075: Integer nodeNumber = numberCache.get(name);
076: if (nodeNumber == null) {
077: try {
078: NodeSearchQuery query = new NodeSearchQuery(this );
079: BasicFieldValueConstraint constraint = new BasicFieldValueConstraint(
080: query.getField(getField("name")), name);
081: query.setConstraint(constraint);
082: Iterator<MMObjectNode> i = getNodes(query).iterator();
083: if (i.hasNext()) {
084: MMObjectNode node = i.next();
085: int rtn = node.getIntValue("destination");
086: numberCache.put(name, rtn);
087: return rtn;
088: } else {
089: numberCache.put(name, NOT_FOUND);
090: return -1;
091: }
092: } catch (SearchQueryException sqe) {
093: log.error(sqe.toString());
094: return -1;
095: }
096: } else {
097: return nodeNumber.intValue();
098: }
099: }
100:
101: /**
102: * Obtain the alias of a node. If a node has more aliases, it returns only one.
103: * Which one is not specified.
104: * @param number the number of the node
105: * @return the alias of the node, or null if it does not exist
106: * @see #getNumber
107: * @todo No caching here?
108: */
109: public String getAlias(int number) {
110: NodeSearchQuery query = new NodeSearchQuery(this );
111: BasicFieldValueConstraint constraint = new BasicFieldValueConstraint(
112: query.getField(getField("destination")), number);
113: query.setConstraint(constraint);
114: try {
115: Iterator<MMObjectNode> i = getNodes(query).iterator();
116: if (i.hasNext()) {
117: MMObjectNode node = i.next();
118: return node.getStringValue("name");
119: } else {
120: return null;
121: }
122: } catch (SearchQueryException sqe) {
123: log.error(sqe.toString());
124: return null;
125:
126: }
127: }
128:
129: /**
130: * Obtain the aliases of a node. If a node has more aliases, it returns only one.
131: * Which one is not specified.
132: * @param number the number of the node
133: * @return a List of the aliases of the node, or an emoty list if none exist
134: * @see #getAlias
135: */
136: public List<String> getAliasList(int number) {
137: NodeSearchQuery query = new NodeSearchQuery(this );
138: BasicFieldValueConstraint constraint = new BasicFieldValueConstraint(
139: query.getField(getField("destination")), number);
140: query.setConstraint(constraint);
141: List<String> aliasList = new ArrayList<String>();
142: try {
143: for (MMObjectNode node : getNodes(query)) {
144: aliasList.add(node.getStringValue("name"));
145: }
146: } catch (SearchQueryException sqe) {
147: log.error(sqe.toString());
148: }
149: return aliasList;
150: }
151:
152: /**
153: * Obtain a node from the cloud through its alias
154: * @param alias the alias of the desired node
155: * @return the node, or null if the alias does not exist
156: * @throws RuntimeException if the alias exists but the node itself doesn't (this indicates
157: * an inconsistency in the database)
158: * @see #getNumber
159: */
160: public MMObjectNode getAliasedNode(String alias) {
161: MMObjectNode node = null;
162: int nr = getNumber(alias);
163: if (nr > 0) {
164: try {
165: node = getNode(nr);
166: } catch (RuntimeException e) {
167: log.error("Alias '" + alias
168: + "' points to non-existing node with number "
169: + nr);
170: throw e;
171: }
172: }
173: return node;
174: }
175:
176: /**
177: * Creates an alias for the node with the given number, and updates the alias cache.
178: *
179: * @since MMBase-1.7
180: */
181: public void createAlias(String alias, int number) {
182: createAlias(alias, number, "system");
183: }
184:
185: /**
186: * Creates an alias for the node with the given number, and updates the alias cache.
187: *
188: * @since MMBase-1.8
189: */
190: public void createAlias(String alias, int number, String owner) {
191: MMObjectNode node = getNewNode(owner);
192: node.setValue("name", alias);
193: node.setValue("destination", number);
194: node.insert(owner);
195: numberCache.remove(alias);
196: }
197:
198: /**
199: * Remove a node from the cloud and update the cache
200: * @param node The node to remove.
201: */
202: public void removeNode(MMObjectNode node) {
203: String name = node.getStringValue("name");
204: super .removeNode(node);
205: numberCache.remove(name);
206: }
207:
208: /**
209: * {@inheritDoc}
210: * If a node is changed or newly created, this adds the new or updated alias to the
211: * cache.
212: * @since MMBase-1.7.1
213: */
214: public boolean nodeRemoteChanged(String machine, String number,
215: String builder, String ctype) {
216: if (builder.equals(getTableName())) {
217: if (ctype.equals("c") || ctype.equals("n")) {
218: // should remove aliasses referencing this number from numberCache here
219: MMObjectNode node = getNode(number);
220: numberCache.put(node.getStringValue("name"), node
221: .getIntegerValue("destination"));
222: } else if (ctype.equals("d")) {
223: Integer n = Integer.valueOf(number);
224: Iterator<Map.Entry<String, Integer>> i = numberCache
225: .entrySet().iterator();
226: while (i.hasNext()) {
227: Map.Entry<String, Integer> entry = i.next();
228: Object value = entry.getValue();
229: if (n.equals(value)) {
230: i.remove();
231: }
232: }
233: }
234: }
235: return super.nodeRemoteChanged(machine, number, builder, ctype);
236: }
237:
238: }
|