/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/
package org.restlet.ext.sip;
import java.util.List;
import org.restlet.Client;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.ext.sip.internal.SipInboundRequest;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;
import org.restlet.resource.UniformResource;
/**
* Client-side resource for the sip protocol. Acts like a proxy of a target
* resource.<br>
* <br>
* This class changes the semantics of the {@link UniformResource#getRequest()}
* and {@link UniformResource#getResponse()} methods. Since a clientResource may
* receive severals responses for a single request (in case of interim
* response), the {@link #getResponse()} method returns the last received
* response object. The Request object returned by the {@link #getRequest()} is
* actually a prototype which is cloned (except the representation) just before
* the {@link #handle()} method is called.<br>
* <br>
* Users must be aware that by most representations can only be read or written
* once. Some others, such as {@link StringRepresentation} stored the entity in
* memory which can be read several times but has the drawback to consume
* memory.<br>
* <br>
* Concurrency note: instances of the class are not designed to be shared among
* several threads. If thread-safety is necessary, consider using the
* lower-level {@link Client} class instead.
*
* @author Thierry Boileau, Jerome Louvel
*/
public class SipClientResource extends ClientResource {
/**
* Creates a client resource that proxy calls to the given Java interface
* into Restlet method calls.
*
* @param <T>
* @param context
* The context.
* @param reference
* The target reference.
* @param resourceInterface
* The annotated resource interface class to proxy.
* @return The proxy instance.
*/
public static <T> T create(Context context, Reference reference,
Class<? extends T> resourceInterface) {
SipClientResource clientResource = new SipClientResource(context,
reference);
return clientResource.wrap(resourceInterface);
}
/**
* Creates a client resource that proxy calls to the given Java interface
* into Restlet method calls.
*
* @param <T>
* @param resourceInterface
* The annotated resource interface class to proxy.
* @return The proxy instance.
*/
public static <T> T create(Reference reference,
Class<? extends T> resourceInterface) {
return create(null, reference, resourceInterface);
}
/**
* Creates a client resource that proxy calls to the given Java interface
* into Restlet method calls.
*
* @param <T>
* @param uri
* The target URI.
* @param resourceInterface
* The annotated resource interface class to proxy.
* @return The proxy instance.
*/
public static <T> T create(String uri, Class<? extends T> resourceInterface) {
return create(null, new Reference(uri), resourceInterface);
}
/**
* Constructor.
*
* @param context
* The context.
* @param uri
* The target URI.
*/
public SipClientResource(Context context, java.net.URI uri) {
this(context, SipMethod.INVITE, uri);
}
/**
* Constructor.
*
* @param context
* The context.
* @param method
* The method to call.
* @param uri
* The target URI.
*/
public SipClientResource(Context context, Method method, java.net.URI uri) {
this(context, method, new Reference(uri));
}
/**
* Constructor.
*
* @param context
* The context.
* @param method
* The method to call.
* @param reference
* The target reference.
*/
public SipClientResource(Context context, Method method, Reference reference) {
this(context, new SipRequest(method, reference), new SipResponse(null));
}
/**
* Constructor.
*
* @param context
* The context.
* @param method
* The method to call.
* @param uri
* The target URI.
*/
public SipClientResource(Context context, Method method, String uri) {
this(context, method, new Reference(uri));
}
/**
* Constructor.
*
* @param context
* The context.
* @param reference
* The target reference.
*/
public SipClientResource(Context context, Reference reference) {
this(context, SipMethod.INVITE, reference);
}
/**
* Constructor.
*
* @param context
* The current context.
* @param request
* The handled request.
* @param response
* The handled response.
*/
public SipClientResource(Context context, SipRequest request,
SipResponse response) {
super(context, request, response);
}
/**
* Constructor.
*
* @param context
* The context.
* @param uri
* The target URI.
*/
public SipClientResource(Context context, String uri) {
this(context, SipMethod.INVITE, uri);
}
/**
* Constructor.
*
* @param uri
* The target URI.
*/
public SipClientResource(java.net.URI uri) {
this(Context.getCurrent(), null, uri);
}
/**
* Constructor.
*
* @param method
* The method to call.
* @param uri
* The target URI.
*/
public SipClientResource(Method method, java.net.URI uri) {
this(Context.getCurrent(), method, uri);
}
/**
* Constructor.
*
* @param method
* The method to call.
* @param reference
* The target reference.
*/
public SipClientResource(Method method, Reference reference) {
this(Context.getCurrent(), method, reference);
}
/**
* Constructor.
*
* @param method
* The method to call.
* @param uri
* The target URI.
*/
public SipClientResource(Method method, String uri) {
this(Context.getCurrent(), method, uri);
}
/**
* Constructor.
*
* @param reference
* The target reference.
*/
public SipClientResource(Reference reference) {
this(Context.getCurrent(), null, reference);
}
/**
* Constructor.
*
* @param resource
* The client resource to copy.
*/
public SipClientResource(SipClientResource resource) {
super();
SipRequest request = new SipRequest(resource.getRequest());
SipResponse response = new SipResponse(request);
setNext(resource.getNext());
setFollowingRedirects(resource.isFollowingRedirects());
setRetryOnError(resource.isRetryOnError());
setRetryDelay(resource.getRetryDelay());
setRetryAttempts(resource.getRetryAttempts());
init(resource.getContext(), request, response);
}
/**
* Constructor.
*
* @param request
* The handled request.
* @param response
* The handled response.
*/
public SipClientResource(SipRequest request, SipResponse response) {
this(Context.getCurrent(), request, response);
}
/**
* Constructor.
*
* @param uri
* The target URI.
*/
public SipClientResource(String uri) {
this(Context.getCurrent(), null, uri);
}
/**
* Confirms that the client has received a final response to an INVITE
* request.
*
* @throws ResourceException
* @see <a href="http://tools.ietf.org/html/rfc2543#section-4.2.2">ACK
* method</a>
*/
public void ack() throws ResourceException {
handle(SipMethod.ACK);
}
/**
* Confirms that the client has received a final response to an INVITE
* request.
*
* @param representation
* The entity to send.
* @throws ResourceException
* @see <a href="http://tools.ietf.org/html/rfc2543#section-4.2.2">ACK
* method</a>
*/
public void ack(Representation representation) throws ResourceException {
handle(SipMethod.ACK, representation);
}
/**
* Indicates to the server that the user agent wishes to release the call.
*
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2543#section-4.2.4">BYE method</a>
*/
public Representation bye() throws ResourceException {
return handle(SipMethod.BYE);
}
/**
* Cancels a pending request with the same Call-ID, To, From and CSeq
* (sequence number only) header field values.
*
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2543#section-4.2.5">CANCEL
* method</a>
*/
public void cancel() throws ResourceException {
handle(SipMethod.CANCEL);
}
@Override
public Request createRequest(Request prototype) {
return new SipRequest((SipRequest) prototype);
}
@Override
protected Response createResponse(Request request) {
return new SipResponse(request);
}
/**
* Returns the request's command sequence.
*
* @return The request's command sequence.
*/
public String getCommandSequence() {
return getRequest().getCommandSequence();
}
/**
* Returns the request initiator's address.
*
* @return The request initiator's address.
*/
public Address getFrom() {
return getRequest().getFrom();
}
@Override
public SipRequest getRequest() {
return (SipRequest) super.getRequest();
}
/**
* Returns the request's call ID.
*
* @return The request's call ID.
*/
public String getRequestCallId() {
return getRequest().getCallId();
}
@Override
public SipResponse getResponse() {
return (SipResponse) super.getResponse();
}
/**
* Returns the response's call ID.
*
* @return The response's call ID.
*/
public String getResponseCallId() {
return getResponse().getCallId();
}
/**
* Returns the request's list of Via entries.
*
* @return The request's list of Via entries.
*/
public List<SipRecipientInfo> getSipRequestRecipientsInfo() {
return getRequest().getSipRecipientsInfo();
}
/**
* Returns the response's list of Via entries.
*
* @return The response's list of Via entries.
*/
public List<SipRecipientInfo> getSipResponseRecipientsInfo() {
return getResponse().getSipRecipientsInfo();
}
/**
* Returns the request recipient's address.
*
* @return The request recipient's address.
*/
public Address getTo() {
return getRequest().getTo();
}
/**
* Communicating mid-session signaling information along the signaling path
* for the call.
*
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2976#section-2">INFO method</a>
*/
public Representation info() throws ResourceException {
return handle(SipMethod.INFO);
}
/**
* Communicating mid-session signaling information along the signaling path
* for the call.
*
* @param representation
* An optional representation.
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2976#section-2">INFO method</a>
*/
public Representation info(Representation representation)
throws ResourceException {
return handle(SipMethod.INFO, representation);
}
/**
* Indicates that the user or service is being invited to participate in a
* session.
*
* @return The optional result entity.
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2543#section-4.2.1">INVITE
* method</a>
*/
public Representation invite() throws ResourceException {
return handle(SipMethod.INVITE);
}
/**
* Indicates that the user or service is being invited to participate in a
* session.
*
* @param representation
* An optional representation.
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2543#section-4.2.1">INVITE
* method</a>
*/
public Representation invite(Representation representation)
throws ResourceException {
return handle(SipMethod.INVITE, representation);
}
/**
* Informs subscribers of changes in state to which the subscriber has a
* subscription.
*
* @param representation
* The notification representation.
* @return The optional result entity.
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc3265#section-3.2">NOTIFY method</a>
*/
public Representation notify(Representation representation)
throws ResourceException {
return handle(SipMethod.NOTIFY, representation);
}
/**
* Queries a SIP server as to its capabilities.
*
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2543#section-4.2.3">OPTIONS
* method</a>
*/
public Representation options() throws ResourceException {
return handle(SipMethod.OPTIONS);
}
/**
* Creates, modifies, and removes event state associated with an
* address-of-record.
*
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc3903#section-4">PUBLISH method</a>
*/
public void publish() throws ResourceException {
handle(SipMethod.PUBLISH);
}
/**
* Creates, modifies, and removes event state associated with an
* address-of-record.
*
* @param representation
* The optional request entity.
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc3903#section-4">PUBLISH method</a>
*/
public void publish(Representation representation) throws ResourceException {
handle(SipMethod.PUBLISH, representation);
}
/**
* Indicates that the target recipient should contact a third party using
* the contact information provided in the request.
*
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc3515#section-2">REFER method</a>
*/
public void refer() throws ResourceException {
handle(SipMethod.REFER);
}
/**
* Registers the address listed in the To header field with a SIP server.
*
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2543#section-4.2.6">REGISTER
* method</a>
*/
public void register() throws ResourceException {
handle(SipMethod.REGISTER);
}
/**
* Registers the address listed in the To header field with a SIP server.
*
* @param to
* The To header field.
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc2543#section-4.2.6">REGISTER
* method</a>
*/
public void register(Address to) throws ResourceException {
SipInboundRequest request = (SipInboundRequest) getRequest();
request.setTo(to);
handle(SipMethod.REGISTER);
}
/**
* Sets the identifier of the call.
*
* @param callId
* The identifier of the call.
*/
public void setCallId(String callId) {
getRequest().setCallId(callId);
}
/**
* Sets the identifier of the command.
*
* @param commandSequence
* The identifier of the command.
*/
public void setCommandSequence(String commandSequence) {
getRequest().setCommandSequence(commandSequence);
}
/**
* Sets the description of the request's initiator.
*
* @param from
* The description of the request's initiator.
*/
public void setFrom(Address from) {
getRequest().setFrom(from);
}
@Override
public void setRequest(Request request) {
if (request instanceof SipRequest) {
super.setRequest(request);
} else {
throw new IllegalArgumentException(
"Only SipRequest instances are allowed as parameter");
}
}
/**
* Sets the request's call ID.
*
* @param callId
* The call ID.
*/
public void setRequestCallId(String callId) {
getRequest().setCallId(callId);
}
@Override
public void setResponse(Response response) {
if (response instanceof SipResponse) {
super.setResponse(response);
} else {
throw new IllegalArgumentException(
"Only SipResponse instances are allowed as parameter");
}
}
/**
* Sets the logical recipient of the request.
*
* @param to
* The logical recipient of the request.
*/
public void setTo(Address to) {
getRequest().setTo(to);
}
/**
* Requests current state and state updates from a remote node.
*
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc3265#section-3.1">SUBSCRIBE
* method</a>
*/
public void subscribe() throws ResourceException {
handle(SipMethod.SUBSCRIBE);
}
/**
* Requests current state and state updates from a remote node.
*
* @param representation
* The optional request entity.
* @throws ResourceException
* @see <a http://tools.ietf.org/html/rfc3265#section-3.1">SUBSCRIBE
* method</a>
*/
public void subscribe(Representation representation)
throws ResourceException {
handle(SipMethod.SUBSCRIBE, representation);
}
}