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.basic;
011:
012: import org.mmbase.framework.*;
013: import java.util.*;
014: import java.io.*;
015: import javax.servlet.ServletRequest;
016: import javax.servlet.http.HttpServletRequest;
017: import org.mmbase.util.*;
018: import org.mmbase.util.xml.Instantiator;
019: import org.mmbase.bridge.Node;
020: import org.mmbase.bridge.Cloud;
021: import org.mmbase.util.functions.*;
022: import org.mmbase.util.transformers.Url;
023: import org.mmbase.util.transformers.CharTransformer;
024: import org.mmbase.util.logging.Logger;
025: import org.mmbase.util.logging.Logging;
026: import org.w3c.dom.Element;
027: import org.w3c.dom.NodeList;
028:
029: /**
030: * The Basic framework is based on a list of {@link UrlConverter}s. It is
031: * configured with an XML 'framework.xml'.
032: *
033: * @author Michiel Meeuwissen
034: * @version $Id: BasicFramework.java,v 1.12 2008/02/24 10:46:20 michiel Exp $
035: * @since MMBase-1.9
036: */
037: public class BasicFramework extends Framework {
038: private static final Logger log = Logging
039: .getLoggerInstance(BasicFramework.class);
040:
041: private static final CharTransformer paramEscaper = new Url(
042: Url.ESCAPE);
043:
044: public static final String XSD = "basicframework.xsd";
045: public static final String NAMESPACE = "http://www.mmbase.org/xmlns/basicframework";
046:
047: static {
048: XMLEntityResolver.registerSystemID(NAMESPACE + ".xsd", XSD,
049: Framework.class);
050: }
051:
052: protected final ChainedUrlConverter urlConverter = new ChainedUrlConverter();
053:
054: protected final LocalizedString description = new LocalizedString(
055: "description");
056:
057: protected final Map<Setting<?>, Object> settingValues = new HashMap<Setting<?>, Object>();
058:
059: public BasicFramework(Element el) {
060: configure(el);
061: }
062:
063: public BasicFramework() {
064: urlConverter.add(new BasicUrlConverter(this ));
065: }
066:
067: public String getUrl(String path, Map<String, Object> parameters,
068: Parameters frameworkParameters, boolean escapeAmps)
069: throws FrameworkException {
070: return urlConverter.getUrl(path, parameters,
071: frameworkParameters, escapeAmps);
072: }
073:
074: public String getProcessUrl(String path,
075: Map<String, Object> parameters,
076: Parameters frameworkParameters, boolean escapeAmps)
077: throws FrameworkException {
078: return urlConverter.getUrl(path, parameters,
079: frameworkParameters, escapeAmps);
080: }
081:
082: public String getInternalUrl(String page,
083: Map<String, Object> params, Parameters frameworkParameters)
084: throws FrameworkException {
085: if (log.isDebugEnabled()) {
086: log.debug("calling urlConverter " + urlConverter);
087: }
088: return urlConverter.getInternalUrl(page, params,
089: frameworkParameters);
090: }
091:
092: public String getName() {
093: return "BASIC";
094: }
095:
096: /**
097: * Configures the framework by reading its config file 'config/framework.xml'
098: * containing a list with UrlConverters.
099: */
100: protected void configure(Element el) {
101: log.info("Configuring " + getClass() + " with "
102: + el.getOwnerDocument().getDocumentURI());
103: try {
104: description.fillFromXml("description", el);
105:
106: NodeList urlconverters = el
107: .getElementsByTagName("urlconverter");
108: for (int i = 0; i < urlconverters.getLength(); i++) {
109: Element element = (Element) urlconverters.item(i);
110: UrlConverter uc;
111: try {
112: uc = (UrlConverter) Instantiator.getInstance(
113: element, (Framework) this );
114: } catch (NoSuchMethodException nsme) {
115: uc = (UrlConverter) Instantiator
116: .getInstance(element);
117: }
118: urlConverter.add(uc);
119: }
120:
121: } catch (Exception e) {
122: log.error(e.getMessage(), e);
123: }
124: BasicUrlConverter buc = new BasicUrlConverter(this );
125: if (!urlConverter.contains(buc)) {
126: urlConverter.add(buc);
127: }
128: log.info("Configured BasicFramework: " + this );
129:
130: }
131:
132: public Block getRenderingBlock(Parameters frameworkParameters) {
133: HttpServletRequest request = frameworkParameters
134: .get(Parameter.REQUEST);
135: State state = State.getState(request);
136: return state.getBlock();
137: }
138:
139: public Block getBlock(Parameters frameworkParameters) {
140: HttpServletRequest request = frameworkParameters
141: .get(Parameter.REQUEST);
142: State state = State.getState(request);
143: log.debug("Getting block for " + frameworkParameters + " -> "
144: + state);
145:
146: // BasicFramework always shows only one component
147: Component component = ComponentRepository.getInstance()
148: .getComponent(
149: frameworkParameters
150: .get(MMBaseUrlConverter.COMPONENT));
151: boolean explicitComponent = component != null;
152: if (state != null && state.isRendering()) {
153: component = state.getBlock().getComponent();
154: } else {
155: log.debug("No state object found");
156: }
157:
158: if (component == null || !component.getName().equals("mynews")) {
159: log.debug("Not currently rendering mynews component");
160: return null;
161: } else {
162: // can explicitely state new block by either 'path' (of mm:url) or framework parameter 'block'.
163: boolean filteredMode = (state == null && explicitComponent)
164: || request.getServletPath().startsWith("/magazine");
165:
166: log.debug("Using " + component);
167:
168: Block block = null;
169: String blockParam = frameworkParameters
170: .get(MMBaseUrlConverter.BLOCK);
171: if (blockParam != null) {
172: block = component.getBlock(blockParam);
173: }
174: /*
175: else {
176: block = component.getBlock(path);
177: if (block == null && path != null && ! "".equals(path)) {
178: log.debug("No block '" + path + "' found");
179: return null;
180: }
181:
182: }
183: */
184: if (block == null && state != null) {
185: block = state.getRenderer().getBlock();
186: }
187:
188: if (block == null) {
189: log.debug("Cannot determin a block for '" + state
190: + "' suppose it a normal link");
191: if (filteredMode) {
192: return null;
193: } else {
194: // throw new IllegalArgumentException("not such block '" + + " for component " + block);
195: }
196: }
197: return block;
198: }
199: //return null;
200: }
201:
202: /**
203: */
204: public Parameter[] getParameterDefinition() {
205: return urlConverter.getParameterDefinition();
206: }
207:
208: public Parameters createParameters() {
209: return new Parameters(getParameterDefinition());
210: }
211:
212: public boolean makeRelativeUrl() {
213: return false;
214: }
215:
216: protected void setBlockParametersForRender(State state,
217: Parameters blockParameters) {
218: for (Map.Entry<String, ?> entry : blockParameters.toMap()
219: .entrySet()) {
220: if (entry.getValue() == null) {
221: log.debug("Using " + entry + " and parameter "
222: + getPrefix(state) + entry.getKey());
223: blockParameters.set(entry.getKey(),
224: state.getRequest().getParameter(
225: getPrefix(state) + entry.getKey()));
226: }
227: }
228: }
229:
230: protected void setBlockParametersForProcess(State state,
231: Parameters blockParameters) {
232: ServletRequest request = state.getRequest();
233: for (Map.Entry<String, ?> entry : blockParameters.toMap()
234: .entrySet()) {
235: request.setAttribute(entry.getKey(), entry.getValue());
236: }
237: }
238:
239: /**
240: * Basic Framework implicitely also processes, i'm not sure if we should require any framework
241: * to do that (perhaps we could say, that the render method must process, if that is necessary,
242: * and not yet done).
243: */
244: public void render(Renderer renderer, Parameters blockParameters,
245: Parameters frameworkParameters, Writer w,
246: Renderer.WindowState windowState) throws FrameworkException {
247: ServletRequest request = frameworkParameters
248: .get(Parameter.REQUEST);
249: State state = State.getState(request);
250: try {
251:
252: request.setAttribute(COMPONENT_CLASS_KEY, "mm_fw_basic");
253:
254: Renderer actualRenderer = state.startBlock(
255: frameworkParameters, renderer);
256: if (!actualRenderer.equals(renderer)) {
257: Parameters newBlockParameters = actualRenderer
258: .getBlock().createParameters();
259: newBlockParameters.setAllIfDefinied(blockParameters);
260: blockParameters = newBlockParameters;
261:
262: }
263:
264: if (state.needsProcess()) {
265: Processor processor = actualRenderer.getBlock()
266: .getProcessor();
267: state.process(processor);
268: log.service("Processing " + actualRenderer.getBlock()
269: + " " + processor);
270: setBlockParametersForProcess(state, blockParameters);
271: processor.process(blockParameters, frameworkParameters);
272: }
273:
274: state.render(actualRenderer);
275: setBlockParametersForRender(state, blockParameters);
276: actualRenderer.render(blockParameters, frameworkParameters,
277: w, windowState);
278: } catch (FrameworkException fe) {
279: Renderer error = new ErrorRenderer(renderer.getType(),
280: renderer.getBlock(), renderer.getUri().toString(),
281: 500, fe);
282: error.render(blockParameters, frameworkParameters, w,
283: windowState);
284: } finally {
285: state.endBlock();
286: }
287: }
288:
289: /**
290: * Think in the basic framework this method is never called explicitely, because processing is
291: * done implicitely by the render
292: */
293: public void process(Processor processor,
294: Parameters blockParameters, Parameters frameworkParameters)
295: throws FrameworkException {
296: HttpServletRequest request = frameworkParameters
297: .get(Parameter.REQUEST);
298: State state = State.getState(request);
299: state.startBlock(frameworkParameters, null);
300: setBlockParametersForProcess(state, blockParameters);
301: processor.process(blockParameters, frameworkParameters);
302: }
303:
304: public Node getUserNode(Parameters frameworkParameters) {
305: Cloud cloud = frameworkParameters.get(Parameter.CLOUD);
306: return cloud.getCloudContext().getAuthentication().getNode(
307: cloud.getUser());
308: }
309:
310: public String getUserBuilder() {
311: return org.mmbase.module.core.MMBase.getMMBase().getMMBaseCop()
312: .getAuthentication().getUserBuilder();
313: }
314:
315: public Map<String, Object> prefix(State state,
316: Map<String, Object> params) {
317: return getMap(state, params);
318: }
319:
320: protected String getPrefix(final State state) {
321: //return "_" + renderer.getBlock().getComponent().getName() + "_" +
322: //renderer.getBlock().getName() + "_" + count + "_";
323: return state.getId() + ":";
324: }
325:
326: protected Map<String, Object> getMap(final State state,
327: final Map<String, Object> params) {
328: return new AbstractMap<String, Object>() {
329: public Set<Map.Entry<String, Object>> entrySet() {
330: return new AbstractSet<Map.Entry<String, Object>>() {
331: public int size() {
332: return params.size();
333: }
334:
335: public Iterator<Map.Entry<String, Object>> iterator() {
336: return new Iterator<Map.Entry<String, Object>>() {
337: private Iterator<Map.Entry<String, Object>> i = params
338: .entrySet().iterator();
339:
340: public boolean hasNext() {
341: return i.hasNext();
342: };
343:
344: public Map.Entry<String, Object> next() {
345: Map.Entry<String, Object> e = i.next();
346: return new org.mmbase.util.Entry<String, Object>(
347: getPrefix(state) + e.getKey(),
348: e.getValue());
349: }
350:
351: public void remove() {
352: throw new UnsupportedOperationException();
353: }
354:
355: };
356: }
357: };
358: }
359: };
360: }
361:
362: public String toString() {
363: return getName() + ": " + description + ": "
364: + urlConverter.toString();
365: }
366:
367: private static final Parameter<Boolean> USE_REQ = new Parameter<Boolean>(
368: "usesession", Boolean.class, Boolean.TRUE);
369:
370: public Parameters createSettingValueParameters() {
371: return new Parameters(Parameter.REQUEST, Parameter.CLOUD,
372: USE_REQ);
373: }
374:
375: protected String getKey(Setting<?> setting) {
376: return "org.mmbase.framework."
377: + setting.getComponent().getName() + "."
378: + setting.getName();
379: }
380:
381: public <C> C getSettingValue(Setting<C> setting,
382: Parameters parameters) {
383: boolean useSession = parameters != null
384: && parameters.get(USE_REQ);
385: if (useSession) {
386: HttpServletRequest req = parameters.get(Parameter.REQUEST);
387: Object v = req.getSession(true).getAttribute(
388: getKey(setting));
389: if (v != null) {
390: return setting.getDataType().cast(v, null, null);
391: }
392: }
393: if (settingValues.containsKey(setting)) {
394: return (C) settingValues.get(setting);
395: } else {
396: return setting.getDataType().getDefaultValue();
397: }
398: }
399:
400: public <C> C setSettingValue(Setting<C> setting,
401: Parameters parameters, C value) {
402: if (parameters == null)
403: throw new SecurityException(
404: "You should provide Cloud and request parameters");
405: boolean useSession = parameters.get(USE_REQ);
406: if (useSession) {
407: C ret = getSettingValue(setting, parameters);
408: HttpServletRequest req = parameters.get(Parameter.REQUEST);
409: req.getSession(true).setAttribute(getKey(setting), value);
410: return ret;
411: } else {
412: Cloud cloud = parameters.get(Parameter.CLOUD);
413: if (cloud.getUser().getRank() == org.mmbase.security.Rank.ADMIN) {
414: return (C) settingValues.put(setting, value);
415: } else {
416: throw new SecurityException("Permission denied");
417: }
418: }
419: }
420:
421: }
|