blob: 592b67c9a7b3e96e63544714608ccbde8d1e7e78 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.portal.impl;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.portal.LinkService;
import org.apache.cocoon.portal.event.ComparableEvent;
import org.apache.cocoon.portal.event.ConvertableEvent;
import org.apache.cocoon.portal.event.Event;
import org.apache.cocoon.portal.event.EventConverter;
import org.apache.cocoon.portal.event.RequestEvent;
import org.apache.cocoon.util.NetUtils;
/**
*
* @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
* @author <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a>
*
* @version $Id$
*/
public class DefaultLinkService
extends AbstractLogEnabled
implements LinkService,
ThreadSafe,
Serviceable,
Disposable,
Contextualizable,
Parameterizable {
/** The converter used to convert an event into a request parameter */
protected EventConverter converter;
/** The service manager */
protected ServiceManager manager;
/** The cocoon context */
protected Context context;
protected Boolean eventsMarshalled;
/** Default port used for http. */
protected int defaultPort = 80;
/** Default port used for https. */
protected int defaultSecurePort = 443;
/**
* @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
*/
public void service(ServiceManager manager) throws ServiceException {
this.manager = manager;
this.converter = (EventConverter)this.manager.lookup(EventConverter.ROLE);
}
/**
* @see org.apache.avalon.framework.parameters.Parameterizable#parameterize(org.apache.avalon.framework.parameters.Parameters)
*/
public void parameterize(Parameters params) throws ParameterException {
this.defaultPort = params.getParameterAsInteger("defaultPort", this.defaultPort);
this.defaultSecurePort = params.getParameterAsInteger("defaultSecurePort", this.defaultSecurePort);
}
/**
* Return the current info for the request.
* @return A LinkInfo object.
*/
protected LinkInfo getInfo() {
final Request request = ContextHelper.getRequest( this.context );
LinkInfo info = (LinkInfo)request.getAttribute(DefaultLinkService.class.getName());
if ( info == null ) {
synchronized ( this ) {
info = (LinkInfo)request.getAttribute(DefaultLinkService.class.getName());
if ( info == null ) {
info = new LinkInfo(request, this.defaultPort, this.defaultSecurePort);
request.setAttribute(DefaultLinkService.class.getName(), info);
}
}
}
return info;
}
/**
* @see org.apache.cocoon.portal.LinkService#isSecure()
*/
public boolean isSecure() {
return ContextHelper.getRequest(this.context).isSecure();
}
/**
* @see org.apache.cocoon.portal.LinkService#encodeURL(String url)
*/
public String encodeURL(String url) {
return ContextHelper.getResponse(this.context).encodeURL(url);
}
/**
* @see org.apache.cocoon.portal.LinkService#getLinkURI(org.apache.cocoon.portal.event.Event)
*/
public String getLinkURI(Event event) {
return this.getLinkURI(event, null);
}
/**
* @see org.apache.cocoon.portal.LinkService#getLinkURI(org.apache.cocoon.portal.event.Event, Boolean)
*/
public String getLinkURI(Event event, Boolean secure) {
if (event == null) {
return this.getRefreshLinkURI(secure);
}
final LinkInfo info = this.getInfo();
final StringBuffer buffer = new StringBuffer(initBuffer(info, event, secure));
boolean hasParams = info.hasParameters();
// add comparable events
final boolean comparableEvent = event instanceof ComparableEvent;
Iterator iter = info.comparableEvents.iterator();
while (iter.hasNext()) {
Object[] objects = (Object[]) iter.next();
ComparableEvent current = (ComparableEvent) objects[0];
if (!comparableEvent || !current.equalsEvent((ComparableEvent) event)) {
if (hasParams) {
buffer.append('&');
} else {
buffer.append('?');
}
try {
buffer.append((String) objects[1]).append('=').append(NetUtils.encode((String) objects[2], "utf-8"));
} catch (UnsupportedEncodingException uee) {
// ignore this as utf-8 is always supported
}
hasParams = true;
}
}
// now add event
hasParams = this.addEvent(buffer, event, hasParams);
return buffer.toString();
}
protected String initBuffer(LinkInfo info, Event event, Boolean secure)
{
return info.getBase(secure);
}
/**
* Add one event to the buffer
* @return Returns true, if the link contains a parameter
*/
protected boolean addEvent(StringBuffer buffer, Event event, boolean hasParams) {
if ( hasParams ) {
buffer.append('&');
} else {
buffer.append('?');
}
StringBuffer value = new StringBuffer("");
String parameterName = processEvent(event, value);
try {
buffer.append(parameterName).append('=').append(NetUtils.encode(value.toString(), "utf-8"));
} catch (UnsupportedEncodingException uee) {
// ignore this as utf-8 is always supported
}
return true;
}
/**
* @see org.apache.cocoon.portal.LinkService#getLinkURI(java.util.List)
*/
public String getLinkURI(List events) {
return this.getLinkURI(events, null);
}
/**
* @see org.apache.cocoon.portal.LinkService#getLinkURI(java.util.List)
*/
public String getLinkURI(List events, Boolean secure) {
if (events == null || events.size() == 0) {
return this.getRefreshLinkURI(secure);
}
final LinkInfo info = this.getInfo();
boolean hasParams = info.hasParameters();
final StringBuffer buffer = new StringBuffer(initBuffer(info, events, secure));
// add comparable events
Iterator iter = info.comparableEvents.iterator();
while (iter.hasNext()) {
Object[] objects = (Object[]) iter.next();
ComparableEvent current = (ComparableEvent) objects[0];
Iterator eventIterator = events.iterator();
boolean found = false;
while (!found && eventIterator.hasNext()) {
final Object inEvent = eventIterator.next();
if (inEvent instanceof ComparableEvent
&& current.equalsEvent((ComparableEvent) inEvent)) {
found = true;
}
}
if (!found) {
if (hasParams) {
buffer.append('&');
} else {
buffer.append('?');
}
try {
buffer.append((String) objects[1]).append('=').append(NetUtils.encode((String) objects[2], "utf-8"));
} catch (UnsupportedEncodingException uee) {
// ignore this as utf-8 is always supported
}
hasParams = true;
}
}
// now add events
iter = events.iterator();
while (iter.hasNext()) {
final Object current = iter.next();
if (current instanceof Event) {
hasParams = this.addEvent(buffer, (Event) current, hasParams);
} else if ( current instanceof ParameterDescription ) {
if (hasParams) {
buffer.append('&');
} else {
buffer.append('?');
hasParams = true;
}
buffer.append(((ParameterDescription) current).parameters);
}
}
return buffer.toString();
}
protected String initBuffer(LinkInfo info, List events, Boolean secure) {
return info.getBase(secure);
}
/**
* @see org.apache.cocoon.portal.LinkService#addEventToLink(org.apache.cocoon.portal.event.Event)
*/
public void addEventToLink(Event event) {
if (event == null) {
return;
}
StringBuffer value = new StringBuffer("");
String parameterName = processEvent(event, value);
final LinkInfo info = this.getInfo();
if (event instanceof ComparableEvent) {
// search if we already have an event for this!
final Iterator iter = info.comparableEvents.iterator();
boolean found = false;
while (!found && iter.hasNext()) {
Object[] objects = (Object[])iter.next();
if (((ComparableEvent) objects[0]).equalsEvent((ComparableEvent) event)) {
found = true;
info.comparableEvents.remove(objects);
}
}
info.comparableEvents.add(new Object[]{event, parameterName, value.toString()});
} else {
this.addParameterToLink(parameterName, value.toString());
}
}
/**
* @see org.apache.cocoon.portal.LinkService#addParameterToLink(java.lang.String, java.lang.String)
*/
public void addParameterToLink(String name, String value) {
final LinkInfo info = this.getInfo();
info.addParameterToBase(name, value);
}
/**
* @see org.apache.cocoon.portal.LinkService#addUniqueParameterToLink(java.lang.String, java.lang.String)
*/
public void addUniqueParameterToLink(String name, String value) {
final LinkInfo info = this.getInfo();
info.deleteParameterFromBase(name);
this.addParameterToLink(name, value);
}
/**
* @see org.apache.cocoon.portal.LinkService#getRefreshLinkURI()
*/
public String getRefreshLinkURI() {
return this.getRefreshLinkURI(null);
}
/**
* @see org.apache.cocoon.portal.LinkService#getRefreshLinkURI(java.lang.Boolean)
*/
public String getRefreshLinkURI(Boolean secure) {
final LinkInfo info = this.getInfo();
final StringBuffer buffer = new StringBuffer(info.getBase(secure));
// add comparable events
Iterator iter = info.comparableEvents.iterator();
boolean hasParams = info.hasParameters();
while (iter.hasNext()) {
Object[] objects = (Object[])iter.next();
if ( hasParams ) {
buffer.append('&');
} else {
buffer.append('?');
}
try {
buffer.append((String)objects[1]).append('=').append(NetUtils.encode((String)objects[2], "utf-8"));
} catch (UnsupportedEncodingException uee) {
// ignore this as utf-8 is always supported
}
hasParams = true;
}
return buffer.toString();
}
/**
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
if (this.manager != null) {
this.manager.release( this.converter );
this.converter = null;
this.manager = null;
}
}
/**
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(Context context) throws ContextException {
this.context = context;
}
private boolean getEventsMarshalled() {
if (this.eventsMarshalled == null) {
this.eventsMarshalled = new Boolean(this.converter.isMarshallEvents());
}
return this.eventsMarshalled.booleanValue();
}
protected String processEvent(Event event, StringBuffer value) {
String parameterName = DEFAULT_REQUEST_EVENT_PARAMETER_NAME;
if (event instanceof ConvertableEvent && getEventsMarshalled()) {
final String eventParName = ((ConvertableEvent) event).getRequestParameterName();
String eventStr = ((ConvertableEvent) event).asString();
if (eventStr == null) {
// Could not convert the event
value.append(this.converter.encode(event));
} else {
parameterName = DEFAULT_CONVERTABLE_EVENT_PARAMETER_NAME;
try {
String eventValue = NetUtils.encode(eventStr, "utf-8");
value.append(eventParName).append('(').append(eventValue).append(')');
} catch (UnsupportedEncodingException uee) {
// ignore this as utf-8 is always supported
}
}
} else {
if (event instanceof RequestEvent) {
final String eventParName = ((RequestEvent) event).getRequestParameterName();
if (eventParName != null) {
parameterName = eventParName;
}
}
value.append(this.converter.encode(event));
}
return parameterName;
}
}