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:
011: package org.mmbase.bridge.util;
012:
013: import java.util.*;
014: import org.mmbase.bridge.*;
015: import org.mmbase.util.*;
016: import org.mmbase.util.functions.*;
017:
018: /**
019: * A bridge Node based on a Map. It can come in handy sometimes to be able to present any Map as an
020: * MMBase Node. E.g. because then it can be accessed in MMBase taglib using mm:field tags.
021:
022: * @author Michiel Meeuwissen
023: * @version $Id: MapNode.java,v 1.11 2008/02/03 17:33:56 nklasens Exp $
024: * @since MMBase-1.8
025: */
026:
027: public class MapNode extends AbstractNode implements Node {
028:
029: /**
030: * This is normally, but not always, a VirtualBuilder. It is not for some builders which have
031: * besides real nodes also virtual nodes, like typedef (cluster nodes) and typerel (allowed relations because of inheritance).
032: */
033: final protected NodeManager nodeManager;
034: final protected Map values;
035: final protected Map<String, Long> sizes = new HashMap<String, Long>();
036: final protected Map<String, Object> wrapper;
037: final protected Map<String, Object> originals = new HashMap<String, Object>();
038:
039: /**
040: * This constructor explicitely specifies the node manager of the Node. This is used for {#getNodeManager} and {#getCloud}.
041: */
042: public MapNode(Map<String, ?> v, NodeManager nm) {
043: values = v;
044: wrapper = new LinkMap<String, Object>(values, originals,
045: LinkMap.Changes.CONSERVE);
046: nodeManager = nm;
047: }
048:
049: /**
050: * A node with a 'virtual' nodemanager will be constructed. This virtual node manager will have
051: * fields which are guessed based on the keys and values of the given map.
052: */
053: public MapNode(Map v, Cloud cloud) {
054: this (v, createVirtualNodeManager(cloud, v));
055:
056: }
057:
058: /**
059: * This allows you to create a Node object even without having a Cloud object. 'Class' security
060: * is used to acquire a Cloud, because every bridge node must be associated with some Cloud
061: * object.
062: */
063: public MapNode(Map v) {
064: this (v, ContextProvider.getDefaultCloudContext().getCloud(
065: "mmbase", "class", null));
066: }
067:
068: protected static NodeManager createVirtualNodeManager(Cloud cloud,
069: final Map map) {
070: return new MapNodeManager(cloud, map);
071: }
072:
073: public Cloud getCloud() {
074: return nodeManager.getCloud();
075: }
076:
077: public NodeManager getNodeManager() {
078: return nodeManager;
079: }
080:
081: @Override
082: public int getNumber() {
083: return Casting.toInt(values.get("number"));
084: }
085:
086: @Override
087: public boolean isNew() {
088: return false;
089: }
090:
091: @Override
092: public boolean isChanged(String fieldName) {
093: return originals.containsKey(fieldName);
094: }
095:
096: @Override
097: public boolean isChanged() {
098: return !originals.isEmpty();
099: }
100:
101: protected void edit(int i) {
102: // always ok.
103: }
104:
105: public Object getValueWithoutProcess(String fieldName) {
106: return values.get(fieldName);
107: }
108:
109: @Override
110: public void setValueWithoutProcess(String fieldName, Object value) {
111: wrapper.put(fieldName, value);
112: }
113:
114: @Override
115: public void setValueWithoutChecks(String fieldName, Object value) {
116: wrapper.put(fieldName, value);
117: }
118:
119: @Override
120: public boolean isNull(String fieldName) {
121: return values.get(fieldName) == null;
122: }
123:
124: @Override
125: protected void setSize(String fieldName, long size) {
126: sizes.put(fieldName, size);
127: }
128:
129: public long getSize(String fieldName) {
130: Long size = sizes.get(fieldName);
131: if (size != null) {
132: return size.longValue();
133: } else {
134: int s = SizeOf.getByteSize(values.get(fieldName));
135: sizes.put(fieldName, (long) s);
136: return s;
137: }
138: }
139:
140: @Override
141: public void commit() {
142: throw new UnsupportedOperationException(
143: "Cannot commit map node");
144: }
145:
146: @Override
147: public void cancel() {
148: }
149:
150: @Override
151: public void delete(boolean deleteRelations) {
152: throw new UnsupportedOperationException(
153: "Cannot delete map node");
154: }
155:
156: @Override
157: public String toString() {
158: return "Map Node" + values;
159: }
160:
161: @Override
162: public void deleteRelations(String type) throws NotFoundException {
163: }
164:
165: @Override
166: public RelationList getRelations(String role,
167: NodeManager nodeManager, String searchDir)
168: throws NotFoundException {
169: return BridgeCollections.EMPTY_RELATIONLIST;
170: }
171:
172: @Override
173: public RelationList getRelations(String role, String nodeManager)
174: throws NotFoundException {
175: return BridgeCollections.EMPTY_RELATIONLIST;
176: }
177:
178: @Override
179: public boolean hasRelations() {
180: return false;
181: }
182:
183: @Override
184: public int countRelatedNodes(NodeManager otherNodeManager,
185: String role, String direction) {
186: return 0;
187:
188: }
189:
190: @Override
191: public NodeList getRelatedNodes(NodeManager nodeManager,
192: String role, String searchDir) {
193: return BridgeCollections.EMPTY_NODELIST;
194: }
195:
196: @Override
197: public int countRelatedNodes(String type) {
198: return 0;
199: }
200:
201: @Override
202: public StringList getAliases() {
203: return BridgeCollections.EMPTY_STRINGLIST;
204: }
205:
206: @Override
207: public void createAlias(String aliasName) {
208: throw new UnsupportedOperationException(
209: "Map nodes have no aliases");
210: }
211:
212: @Override
213: public void deleteAlias(String aliasName) {
214: throw new UnsupportedOperationException(
215: "Map nodes have no aliases");
216: }
217:
218: @Override
219: public Relation createRelation(Node destinationNode,
220: RelationManager relationManager) {
221: throw new UnsupportedOperationException(
222: "Map nodes have no relations");
223: }
224:
225: @Override
226: public void setContext(String context) {
227: throw new UnsupportedOperationException(
228: "Map nodes have no security context");
229: }
230:
231: // javadoc inherited (from Node)
232: @Override
233: public String getContext() {
234: throw new UnsupportedOperationException(
235: "Virtual nodes have no security context");
236: }
237:
238: // javadoc inherited (from Node)
239: @Override
240: public StringList getPossibleContexts() {
241: return BridgeCollections.EMPTY_STRINGLIST;
242: }
243:
244: @Override
245: public boolean mayWrite() {
246: return true;
247: }
248:
249: @Override
250: public boolean mayDelete() {
251: return false;
252: }
253:
254: @Override
255: public boolean mayChangeContext() {
256: return false;
257: }
258:
259: public Collection<Function<?>> getFunctions() {
260: return nodeManager.getFunctions();
261: }
262:
263: @Override
264: protected Function getNodeFunction(String functionName) {
265: return nodeManager.getFunction(functionName);
266: }
267: }
|