001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.portal.impl;
018:
019: import java.io.UnsupportedEncodingException;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.apache.avalon.framework.activity.Disposable;
024: import org.apache.avalon.framework.context.Context;
025: import org.apache.avalon.framework.context.ContextException;
026: import org.apache.avalon.framework.context.Contextualizable;
027: import org.apache.avalon.framework.logger.AbstractLogEnabled;
028: import org.apache.avalon.framework.parameters.ParameterException;
029: import org.apache.avalon.framework.parameters.Parameterizable;
030: import org.apache.avalon.framework.parameters.Parameters;
031: import org.apache.avalon.framework.service.ServiceException;
032: import org.apache.avalon.framework.service.ServiceManager;
033: import org.apache.avalon.framework.service.Serviceable;
034: import org.apache.avalon.framework.thread.ThreadSafe;
035: import org.apache.cocoon.components.ContextHelper;
036: import org.apache.cocoon.environment.Request;
037: import org.apache.cocoon.portal.LinkService;
038: import org.apache.cocoon.portal.event.ComparableEvent;
039: import org.apache.cocoon.portal.event.ConvertableEvent;
040: import org.apache.cocoon.portal.event.Event;
041: import org.apache.cocoon.portal.event.EventConverter;
042: import org.apache.cocoon.portal.event.RequestEvent;
043: import org.apache.cocoon.util.NetUtils;
044:
045: /**
046: *
047: * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
048: * @author <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a>
049: *
050: * @version $Id: DefaultLinkService.java 433543 2006-08-22 06:22:54Z crossley $
051: */
052: public class DefaultLinkService extends AbstractLogEnabled implements
053: LinkService, ThreadSafe, Serviceable, Disposable,
054: Contextualizable, Parameterizable {
055:
056: /** The converter used to convert an event into a request parameter */
057: protected EventConverter converter;
058: /** The service manager */
059: protected ServiceManager manager;
060: /** The cocoon context */
061: protected Context context;
062:
063: protected Boolean eventsMarshalled;
064:
065: /** Default port used for http. */
066: protected int defaultPort = 80;
067: /** Default port used for https. */
068: protected int defaultSecurePort = 443;
069:
070: /**
071: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
072: */
073: public void service(ServiceManager manager) throws ServiceException {
074: this .manager = manager;
075: this .converter = (EventConverter) this .manager
076: .lookup(EventConverter.ROLE);
077: }
078:
079: /**
080: * @see org.apache.avalon.framework.parameters.Parameterizable#parameterize(org.apache.avalon.framework.parameters.Parameters)
081: */
082: public void parameterize(Parameters params)
083: throws ParameterException {
084: this .defaultPort = params.getParameterAsInteger("defaultPort",
085: this .defaultPort);
086: this .defaultSecurePort = params.getParameterAsInteger(
087: "defaultSecurePort", this .defaultSecurePort);
088: }
089:
090: /**
091: * Return the current info for the request.
092: * @return A LinkInfo object.
093: */
094: protected LinkInfo getInfo() {
095: final Request request = ContextHelper.getRequest(this .context);
096: LinkInfo info = (LinkInfo) request
097: .getAttribute(DefaultLinkService.class.getName());
098: if (info == null) {
099: synchronized (this ) {
100: info = (LinkInfo) request
101: .getAttribute(DefaultLinkService.class
102: .getName());
103: if (info == null) {
104: info = new LinkInfo(request, this .defaultPort,
105: this .defaultSecurePort);
106: request.setAttribute(DefaultLinkService.class
107: .getName(), info);
108: }
109: }
110: }
111: return info;
112: }
113:
114: /**
115: * @see org.apache.cocoon.portal.LinkService#isSecure()
116: */
117: public boolean isSecure() {
118: return ContextHelper.getRequest(this .context).isSecure();
119: }
120:
121: /**
122: * @see org.apache.cocoon.portal.LinkService#encodeURL(String url)
123: */
124: public String encodeURL(String url) {
125: return ContextHelper.getResponse(this .context).encodeURL(url);
126: }
127:
128: /**
129: * @see org.apache.cocoon.portal.LinkService#getLinkURI(org.apache.cocoon.portal.event.Event)
130: */
131: public String getLinkURI(Event event) {
132: return this .getLinkURI(event, null);
133: }
134:
135: /**
136: * @see org.apache.cocoon.portal.LinkService#getLinkURI(org.apache.cocoon.portal.event.Event, Boolean)
137: */
138: public String getLinkURI(Event event, Boolean secure) {
139: if (event == null) {
140: return this .getRefreshLinkURI(secure);
141: }
142: final LinkInfo info = this .getInfo();
143: final StringBuffer buffer = new StringBuffer(initBuffer(info,
144: event, secure));
145: boolean hasParams = info.hasParameters();
146:
147: // add comparable events
148: final boolean comparableEvent = event instanceof ComparableEvent;
149: Iterator iter = info.comparableEvents.iterator();
150: while (iter.hasNext()) {
151: Object[] objects = (Object[]) iter.next();
152: ComparableEvent current = (ComparableEvent) objects[0];
153: if (!comparableEvent
154: || !current.equalsEvent((ComparableEvent) event)) {
155: if (hasParams) {
156: buffer.append('&');
157: } else {
158: buffer.append('?');
159: }
160: try {
161: buffer.append((String) objects[1]).append('=')
162: .append(
163: NetUtils.encode(
164: (String) objects[2],
165: "utf-8"));
166: } catch (UnsupportedEncodingException uee) {
167: // ignore this as utf-8 is always supported
168: }
169: hasParams = true;
170: }
171: }
172:
173: // now add event
174: hasParams = this .addEvent(buffer, event, hasParams);
175:
176: return buffer.toString();
177: }
178:
179: protected String initBuffer(LinkInfo info, Event event,
180: Boolean secure) {
181: return info.getBase(secure);
182: }
183:
184: /**
185: * Add one event to the buffer
186: * @return Returns true, if the link contains a parameter
187: */
188: protected boolean addEvent(StringBuffer buffer, Event event,
189: boolean hasParams) {
190: if (hasParams) {
191: buffer.append('&');
192: } else {
193: buffer.append('?');
194: }
195: StringBuffer value = new StringBuffer("");
196: String parameterName = processEvent(event, value);
197: try {
198: buffer.append(parameterName).append('=').append(
199: NetUtils.encode(value.toString(), "utf-8"));
200: } catch (UnsupportedEncodingException uee) {
201: // ignore this as utf-8 is always supported
202: }
203: return true;
204: }
205:
206: /**
207: * @see org.apache.cocoon.portal.LinkService#getLinkURI(java.util.List)
208: */
209: public String getLinkURI(List events) {
210: return this .getLinkURI(events, null);
211: }
212:
213: /**
214: * @see org.apache.cocoon.portal.LinkService#getLinkURI(java.util.List)
215: */
216: public String getLinkURI(List events, Boolean secure) {
217: if (events == null || events.size() == 0) {
218: return this .getRefreshLinkURI(secure);
219: }
220: final LinkInfo info = this .getInfo();
221: boolean hasParams = info.hasParameters();
222: final StringBuffer buffer = new StringBuffer(initBuffer(info,
223: events, secure));
224:
225: // add comparable events
226: Iterator iter = info.comparableEvents.iterator();
227: while (iter.hasNext()) {
228: Object[] objects = (Object[]) iter.next();
229: ComparableEvent current = (ComparableEvent) objects[0];
230:
231: Iterator eventIterator = events.iterator();
232: boolean found = false;
233: while (!found && eventIterator.hasNext()) {
234: final Object inEvent = eventIterator.next();
235: if (inEvent instanceof ComparableEvent
236: && current
237: .equalsEvent((ComparableEvent) inEvent)) {
238: found = true;
239: }
240: }
241: if (!found) {
242: if (hasParams) {
243: buffer.append('&');
244: } else {
245: buffer.append('?');
246: }
247: try {
248: buffer.append((String) objects[1]).append('=')
249: .append(
250: NetUtils.encode(
251: (String) objects[2],
252: "utf-8"));
253: } catch (UnsupportedEncodingException uee) {
254: // ignore this as utf-8 is always supported
255: }
256: hasParams = true;
257: }
258: }
259:
260: // now add events
261: iter = events.iterator();
262: while (iter.hasNext()) {
263: final Object current = iter.next();
264: if (current instanceof Event) {
265: hasParams = this .addEvent(buffer, (Event) current,
266: hasParams);
267: } else if (current instanceof ParameterDescription) {
268: if (hasParams) {
269: buffer.append('&');
270: } else {
271: buffer.append('?');
272: hasParams = true;
273: }
274: buffer
275: .append(((ParameterDescription) current).parameters);
276: }
277: }
278: return buffer.toString();
279: }
280:
281: protected String initBuffer(LinkInfo info, List events,
282: Boolean secure) {
283: return info.getBase(secure);
284: }
285:
286: /**
287: * @see org.apache.cocoon.portal.LinkService#addEventToLink(org.apache.cocoon.portal.event.Event)
288: */
289: public void addEventToLink(Event event) {
290: if (event == null) {
291: return;
292: }
293: StringBuffer value = new StringBuffer("");
294: String parameterName = processEvent(event, value);
295:
296: final LinkInfo info = this .getInfo();
297: if (event instanceof ComparableEvent) {
298: // search if we already have an event for this!
299: final Iterator iter = info.comparableEvents.iterator();
300: boolean found = false;
301: while (!found && iter.hasNext()) {
302: Object[] objects = (Object[]) iter.next();
303: if (((ComparableEvent) objects[0])
304: .equalsEvent((ComparableEvent) event)) {
305: found = true;
306: info.comparableEvents.remove(objects);
307: }
308: }
309: info.comparableEvents.add(new Object[] { event,
310: parameterName, value.toString() });
311: } else {
312: this .addParameterToLink(parameterName, value.toString());
313: }
314: }
315:
316: /**
317: * @see org.apache.cocoon.portal.LinkService#addParameterToLink(java.lang.String, java.lang.String)
318: */
319: public void addParameterToLink(String name, String value) {
320: final LinkInfo info = this .getInfo();
321: info.addParameterToBase(name, value);
322: }
323:
324: /**
325: * @see org.apache.cocoon.portal.LinkService#addUniqueParameterToLink(java.lang.String, java.lang.String)
326: */
327: public void addUniqueParameterToLink(String name, String value) {
328: final LinkInfo info = this .getInfo();
329: info.deleteParameterFromBase(name);
330: this .addParameterToLink(name, value);
331: }
332:
333: /**
334: * @see org.apache.cocoon.portal.LinkService#getRefreshLinkURI()
335: */
336: public String getRefreshLinkURI() {
337: return this .getRefreshLinkURI(null);
338: }
339:
340: /**
341: * @see org.apache.cocoon.portal.LinkService#getRefreshLinkURI(java.lang.Boolean)
342: */
343: public String getRefreshLinkURI(Boolean secure) {
344: final LinkInfo info = this .getInfo();
345:
346: final StringBuffer buffer = new StringBuffer(info
347: .getBase(secure));
348:
349: // add comparable events
350: Iterator iter = info.comparableEvents.iterator();
351: boolean hasParams = info.hasParameters();
352: while (iter.hasNext()) {
353: Object[] objects = (Object[]) iter.next();
354: if (hasParams) {
355: buffer.append('&');
356: } else {
357: buffer.append('?');
358: }
359: try {
360: buffer.append((String) objects[1]).append('=').append(
361: NetUtils.encode((String) objects[2], "utf-8"));
362: } catch (UnsupportedEncodingException uee) {
363: // ignore this as utf-8 is always supported
364: }
365: hasParams = true;
366: }
367: return buffer.toString();
368: }
369:
370: /**
371: * @see org.apache.avalon.framework.activity.Disposable#dispose()
372: */
373: public void dispose() {
374: if (this .manager != null) {
375: this .manager.release(this .converter);
376: this .converter = null;
377: this .manager = null;
378: }
379: }
380:
381: /**
382: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
383: */
384: public void contextualize(Context context) throws ContextException {
385: this .context = context;
386: }
387:
388: private boolean getEventsMarshalled() {
389: if (this .eventsMarshalled == null) {
390: this .eventsMarshalled = new Boolean(this .converter
391: .isMarshallEvents());
392: }
393: return this .eventsMarshalled.booleanValue();
394: }
395:
396: protected String processEvent(Event event, StringBuffer value) {
397: String parameterName = DEFAULT_REQUEST_EVENT_PARAMETER_NAME;
398: if (event instanceof ConvertableEvent && getEventsMarshalled()) {
399: final String eventParName = ((ConvertableEvent) event)
400: .getRequestParameterName();
401: String eventStr = ((ConvertableEvent) event).asString();
402: if (eventStr == null) {
403: // Could not convert the event
404: value.append(this .converter.encode(event));
405: } else {
406: parameterName = DEFAULT_CONVERTABLE_EVENT_PARAMETER_NAME;
407: try {
408: String eventValue = NetUtils.encode(eventStr,
409: "utf-8");
410: value.append(eventParName).append('(').append(
411: eventValue).append(')');
412: } catch (UnsupportedEncodingException uee) {
413: // ignore this as utf-8 is always supported
414: }
415: }
416: } else {
417: if (event instanceof RequestEvent) {
418: final String eventParName = ((RequestEvent) event)
419: .getRequestParameterName();
420: if (eventParName != null) {
421: parameterName = eventParName;
422: }
423: }
424: value.append(this.converter.encode(event));
425: }
426: return parameterName;
427: }
428: }
|