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.framework;
011:
012: import java.util.*;
013: import org.mmbase.util.functions.*;
014: import org.mmbase.util.LocalizedString;
015:
016: import org.mmbase.util.logging.Logger;
017: import org.mmbase.util.logging.Logging;
018:
019: /**
020: * A Block is a representation of a page within a component. It has 2 renderers,
021: * 'head' and 'body', and a processor.
022: *
023: * @author Johannes Verelst
024: * @author Michiel Meeuwissen
025: * @version $Id: Block.java,v 1.33 2008/02/23 16:46:19 michiel Exp $
026: * @since MMBase-1.9
027: */
028: public class Block {
029:
030: private static final Logger log = Logging
031: .getLoggerInstance(Block.class);
032:
033: private final Map<Renderer.Type, Renderer> renderers = new EnumMap<Renderer.Type, Renderer>(
034: Renderer.Type.class);
035: Processor processor;
036:
037: protected Parameter.Wrapper specific;
038:
039: private final String name;
040: private final String mimetype;
041: private final Component parent;
042: private final LocalizedString description;
043: private final LocalizedString title;
044: private final Type[] classification;
045:
046: public Block(String name, String mimetype, Component parent,
047: Type[] cla) {
048: if (name == null)
049: throw new IllegalArgumentException();
050: if (parent == null)
051: throw new IllegalArgumentException();
052: if (cla == null)
053: throw new IllegalArgumentException();
054: this .name = name;
055: this .parent = parent;
056: this .mimetype = mimetype; // can this be null?
057: this .classification = cla;
058: for (Type t : classification) {
059: t.blocks.add(this );
060: }
061: this .description = new LocalizedString(name);
062: this .title = new LocalizedString(name);
063: }
064:
065: /**
066: * Name for this block. Never <code>null</code>
067: */
068: public String getName() {
069: return name;
070: }
071:
072: /**
073: * A localized title for this block.
074: */
075: public LocalizedString getTitle() {
076: return title;
077: }
078:
079: /**
080: * Mimetype for this block. E.g. "text/html".
081: */
082: public String getMimeType() {
083: return mimetype;
084: }
085:
086: /**
087: * Returns the 'classification' of this block. For example the blocks
088: * classified as 'mmbase.admin' are presented in the mmbase admin-pages.
089: */
090: public Type[] getClassification() {
091: return classification;
092: }
093:
094: /**
095: * @todo This method is not yet implemented.
096: */
097: public Type[] getClassification(String filter) {
098: String[] parts = filter.split("\\s*?[,\\s]\\s*");
099: for (Type type : classification) {
100:
101: }
102: return null;
103: }
104:
105: /**
106: * Description for this block. Never <code>null</code>
107: */
108: public LocalizedString getDescription() {
109: return description;
110: }
111:
112: /**
113: * All renderers assiociated with this Block. This is not a public method (it is used to create
114: * the block). Use {@link #getRenderer(Renderer.Type}).
115: */
116: Map<Renderer.Type, Renderer> getRenderers() {
117: return renderers;
118: }
119:
120: /**
121: * @return A renderer for the given Render type. Never <code>null</code>
122: */
123: public Renderer getRenderer(Renderer.Type type) {
124: Renderer rend = renderers.get(type);
125: return rend == null ? type.getEmpty(this ) : rend;
126: }
127:
128: /**
129: * @return The processor associated with this block. Never <code>null</code>
130: */
131: public Processor getProcessor() {
132: return processor == null ? AbstractProcessor.getEmpty(this )
133: : processor;
134: }
135:
136: void addParameters(Parameter... params) {
137: List<Parameter> help = new ArrayList<Parameter>();
138: if (specific != null) {
139: help.addAll(Arrays.asList(specific.getArguments()));
140: }
141: for (Parameter p : params) {
142: help.add(p);
143: }
144: specific = new Parameter.Wrapper(help.toArray(Parameter
145: .emptyArray()));
146: log.debug("Set parameters of " + this + " to " + help);
147: }
148:
149: /**
150: * Before rendering, it may have to be fed with certain parameters. Obtain a parameters
151: * object which this method, fill it, and feed it back into {@link Renderer#render}.
152: */
153: public Parameters createParameters() {
154: if (specific == null) {
155: return new AutodefiningParameters();
156: } else {
157: return new Parameters(specific, new Parameter.Wrapper(
158: getRenderer(Renderer.Type.HEAD).getParameters()),
159: new Parameter.Wrapper(getRenderer(
160: Renderer.Type.BODY).getParameters()),
161: new Parameter.Wrapper(getProcessor()
162: .getParameters()));
163: }
164: }
165:
166: /**
167: * @return the Component from which this block is a part.
168: */
169: public Component getComponent() {
170: return parent;
171: }
172:
173: public String toString() {
174: return getName();
175: }
176:
177: /**
178: * Every block can be assigned a hierarchal 'Type', which can classify it.
179: */
180: public static class Type implements Comparable<Type> {
181: public static final Type ROOT = new Type("ROOT");
182: /**
183: * All unclassified blocks are of this type
184: */
185: public static final Type NO = new Type("");
186:
187: /**
188: * @javadoc
189: */
190: public static Type[] getClassification(String p, boolean create) {
191: if (p == null || "".equals(p))
192: return new Type[] { NO };
193: List<Type> r = new ArrayList<Type>();
194: PARTS: for (String part : p.split("\\s*?[,\\s]\\s*")) {
195: Type t = ROOT;
196: for (String e : part.split("\\.")) {
197: Type proposal = new Type(e, t);
198: int i = t.subs.indexOf(proposal);
199: if (i == -1) {
200: if (create) {
201: t.subs.add(proposal);
202: } else {
203: continue PARTS;
204: }
205: } else {
206: proposal = t.subs.get(i);
207: }
208: Collections.sort(t.subs);
209: t = proposal;
210: }
211: r.add(t);
212: }
213: return r.toArray(new Type[] {});
214: }
215:
216: private final String name;
217: private final Type parent;
218: private int weight = 100;
219: final List<Type> subs = new ArrayList<Type>();
220: final List<Block> blocks = new ArrayList<Block>();
221:
222: private Type(String n) {
223: name = n;
224: parent = null;
225: }
226:
227: protected Type(String n, Type p) {
228: if (n == null)
229: throw new IllegalArgumentException();
230: if (p == null)
231: throw new IllegalArgumentException();
232: name = n;
233: parent = p;
234: }
235:
236: public List<Type> getSubTypes() {
237: return Collections.unmodifiableList(subs);
238: }
239:
240: public List<Block> getBlocks() {
241: return Collections.unmodifiableList(blocks);
242: }
243:
244: public String getName() {
245: return name;
246: }
247:
248: public void setWeight(int w) {
249: weight = w;
250: if (parent != null) {
251: Collections.sort(parent.subs);
252: }
253: }
254:
255: public int getWeight() {
256: return weight;
257: }
258:
259: /**
260: * @todo
261: */
262: public boolean contains(String test) {
263: return false;
264: }
265:
266: Type getParent() {
267: return parent;
268: }
269:
270: public boolean equals(Object o) {
271: if (o instanceof Type) {
272: Type t = (Type) o;
273: return name.equals(t.name) && parent == t.parent;
274: } else {
275: return false;
276: }
277: }
278:
279: public int hashCode() {
280: return name.hashCode();
281: }
282:
283: public String toString() {
284: return name + subs.toString();
285: }
286:
287: public int compareTo(Type t) {
288: int s = weight - t.weight;
289: return s == 0 ? name.compareTo(t.name) : s;
290: }
291: }
292:
293: }
|