Java tutorial
/*- * Copyright (c) * * 2012-2014, Facultad Politcnica, Universidad Nacional de Asuncin. * 2012-2014, Facultad de Ciencias Mdicas, Universidad Nacional de Asuncin. * 2012-2013, Centro Nacional de Computacin, Universidad Nacional de Asuncin. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ package py.una.pol.karaku.services.client; import java.util.concurrent.Executor; import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.task.SyncTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.ws.client.core.WebServiceMessageCallback; import org.springframework.ws.client.core.WebServiceTemplate; import py.una.pol.karaku.exception.KarakuException; import py.una.pol.karaku.services.client.WSInformationProvider.Info; /** * <p> * Clase que sirve de abstraccin para llamada a servicios del tipo SOAP, provee * las funcionalidades bsicas y debe ser heredada por cualquier Servicio que * desee realizar invocaciones. * </p> * <p> * El objetivo de esta clase es que todas las llamadas se realicen mediante * ella. Adems asegura que todas las llamadas sean asncronas, funcionamiento * que es deseado dentro de Karaku. * </p> * <p> * Esta implementacin inyecta un {@link Executor}, encapsula todas sus llamadas * (no validaciones) en un {@link Runnable} y lo lanza. * </p> * <h3> * Formas de utilizacin</h3> * <p> * Para poder utilizar estos mtodos, se muestran los siguientes ejemplos, La * clase Controller invoca a un servicio de obtencin de personas mediante la * URI de la misma, y la clase PersonImporter hereda de {@link WSCaller} para * proveer mecanismos de llamadas a los servicios. * </p> * * <pre> * {@literal @}{@link Component} * public class Controller { * * {@literal @}{@link Autowired} * PersonImporter personImporter; // Clase que injecta {@link WSCaller} * * public <b>{@link Void}</b> loadData() { * personImporter.getByUri( * uri, * new {@link WSCallBack}<List<Persona>>() { * public void onSucess(List<Persona> result) { * for (Persona p : result) { * System.out.println(p.getNombre()); * } * } * public void onFailure({@link KarakuException} ke) { * System.out.println(ke.getMessage()); * } * }); * } * ... * } * * {@literal @}{@link Component} * public class PersonImporter extends {@link WSCaller} { * * public <b>{@link Void}</b> getByUri(String uri, {@link WSCallBack}<List<Persona>> WSCallBack) { * PersonaRequest Object = new PersonaRequest(uri); * {@link #call(Object, WSCallBack)}; * } * * } * </pre> * * <b>Si invocamos de la siguiente manera</b> * * <pre> * System.out.printLn("Llamando al servicio"); * controler.loadData(); * System.out.printLn("Finalizando la llamada"); * </pre> * * <b>Producir la siguiente salida</b> * * <pre> * Llamando al servicio * Finalizando la llamada * ?lvar Nez Cabeza de Vaca * </pre> * * <p> * Siendo <b>?lvar Nez Cabeza de Vaca</b> el resultado del servicio, podemos * notar que no son mtodos sncronos, por ello la importancia del * {@link WSCallBack}. * </p> * * * * @author Arturo Volpe * @since 2.1.3 * @version 1.0 Jun 11, 2013 * @see WSCallBack * @see Info * @see #call(Object, WSCallBack) Invocacin normal * @see #call(Object, Info, WSCallBack) Invocacin TypeSafe * @see #call(Object, Class, WSCallBack) Invocacin con informacin del servicio * */ @Component public class WSCaller { private static final String REQUEST_CAN_NOT_BE_NULL = "Request can not be null"; private final Logger log = LoggerFactory.getLogger(getClass()); /** * Template utilizado para realizar llamadas al servicio a travs de la * Abstraccin de Spring */ @Autowired private WebServiceTemplate template; /** * Proveedor de URL's, se inyecta la interfaz por que cualquier * implementacin sirve. */ @Autowired private WSInformationProvider provider; @Autowired private SyncTaskExecutor executor; @Autowired private WSSecurityInterceptor interceptor; /** * Invoca a un servicio en un hilo paralelo y ejecuta al {@link WSCallBack} * una vez finalizado. * <p> * Para obtener informacin acerca del servicio utiliza la clase de * <code>request</code>, por ello no puede ser nula. * </p> * <p> * Se puede notar adems, de que este mtodo no es TypeSafe, es decir, este * mtodo puede ser invocado pasando parmetros que no tienen sentido, como * un {@link WSCallBack} que no corresponde al resultado del servicio. * </p> * * @param request * no nula, la informacin que ser serializada y enviada. * @param callback * clase que ser invocada cuando se retorne el servicio. * @see #call(Object, Class, WSCallBack) */ public <T> void call(@NotNull T request, @NotNull WSCallBack<?> callback) { if (request == null) { throw new IllegalArgumentException(REQUEST_CAN_NOT_BE_NULL); } Info info = provider.getInfoByReturnType(request.getClass()); call(executor, request, info, callback); } /** * Invoca a un servicio, este mtodo es TypeSafe, pues tambin recibe el * tipo de la respuesta que espera. * <p> * Utiliza el parmetro <code>request</code> para definir el tipo de * servicio al que desea invocar. El {@link WSCallBack} debe de ser del tipo * de la respuesta (<code>responseType</code>), pues se espera que la misma * sea de ese tipo. * </p> * <p> * Este mtodo es TypeSafe, es decir nunca dar un error de casteo entre * clases, su utilizacin es muy similar a la de * {@link #call(Object, WSCallBack)}. * </p> * * @see #call(Object, WSCallBack) * @param request * no nula, la informacin que ser serializada. * @param responseType * tipo de la respuesta para des-serializar * @param callback * clase que ser invocada con la respuesta */ public <T, K> void call(@NotNull T request, Class<K> responseType, @NotNull WSCallBack<K> callback) { if (request == null) { throw new IllegalArgumentException(REQUEST_CAN_NOT_BE_NULL); } Info info = provider.getInfoByReturnType(request.getClass()); call(executor, request, info, callback); } public <T> void call(final Object request, final Info info, final WSCallBack<T> callBack) { call(executor, request, info, callBack); } /** * Invoca al servicio definido en <code>info</code>, la invocacin se * realiza en otro hilo, encapsula todos los * {@link WebServiceMessageCallback} definidos en * {@link WSSecurityInterceptor#getWebServiceMessageCallback(Info)} para * agregar la seguridad. * <p> * Este mtodo es el punto de acceso a todos los servicios de Karaku. * </p> * * @param request * objeto que ser serializado para realizar la invocacin * @param info * informacin acerca del servicio. * @param callBack * callBack que ser invocado cuando se reciba la llamada del * servicio. */ public <T> void call(final Executor executor, final Object request, final Info info, final WSCallBack<T> callBack) { if (callBack == null) { throw new IllegalArgumentException("CallBack no puede ser nulo"); } executor.execute(new Runnable() { @Override @SuppressWarnings("unchecked") public void run() { try { log.trace("Calling WebService with uri {}", info.getUrl()); WebServiceMessageCallback wsmc = interceptor.getWebServiceMessageCallback(info); T toRet = (T) template.marshalSendAndReceive(info.getUrl(), request, wsmc); log.trace("Web service call ended"); callBack.onSucess(toRet); } catch (Exception e) { log.debug("Error in ws", e); callBack.onFailure(e); } } }); } }