Package org.butor.json.service

Source Code of org.butor.json.service.DefaultServiceManager

/*******************************************************************************
* Copyright 2013 butor.com
*
* Licensed 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.butor.json.service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.butor.json.CommonRequestArgs;
import org.butor.json.JsonHelper;
import org.butor.json.JsonServiceRequest;
import org.butor.utils.ApplicationException;
import org.butor.utils.CommonMessageID;
import org.butor.utils.Message;
import org.butor.utils.Message.MessageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.google.common.base.Preconditions;

public class DefaultServiceManager implements ServiceManager,InitializingBean,BeanFactoryAware {
  protected Logger _logger = LoggerFactory.getLogger(getClass());
  private JsonHelper _jsh = new JsonHelper();
 
  private PlatformTransactionManager transactionManager;
  private BeanFactory beanFactory;
 
 
  private ConcurrentMap<String, ServiceComponent> _cmps =
      new ConcurrentHashMap<String, ServiceComponent>();

  private List<ServiceComponent> _components;

  @Override
  public void registerServices(List<ServiceComponent> components_) {
    for (ServiceComponent ser : components_)
      registerService(ser);
  }

  @Override
  public void registerService(ServiceComponent serviceCmp_) {
    String ns = serviceCmp_.getNamespace();
    if (_cmps.containsKey(ns)) {
      _logger.error(String.format("Namespace %s has been used by component %s",
          ns, _cmps.get(ns).toString()));
      return;
    }
    _cmps.put(ns, serviceCmp_);
  }

  @Override
  public void unregisterService(ServiceComponent cmp_) {
    _cmps.remove(cmp_.getNamespace());
  }

  @Override
  public void invoke(final Context ctx_) {
    JsonServiceRequest req = (JsonServiceRequest)ctx_.getRequest();
    final String namespace = req.getNamespace();
    final ServiceComponent cmp = _cmps.get(namespace);
    if (cmp == null) {
      String msg = String.format("No service component found with ns=%s", namespace);
      _logger.info(msg);
      return;
    }


    List<?> params = _jsh.deserialize(req.getServiceArgsJson(), List.class);
    int nbArgs = params.size() +1; // +1 for context arg

    final String serviceName = req.getService();
    final Method serviceMethod = cmp.getService(serviceName, nbArgs);

    if (serviceMethod == null) {
      String msg = String.format("No service=%s found with ns=%s",
          serviceName, namespace);
      _logger.info(msg);
      ctx_.getResponseHandler().addMessage(new Message(0, MessageType.ERROR, msg));
      return;
    }

    try {
      final CommonRequestArgs cr = new CommonRequestArgs();
      cr.setLang(req.getLang());
      cr.setReqId(req.getReqId());
      cr.setSessionId(req.getSessionId());
      cr.setUserId(req.getUserId());
      Context ctx = new Context() {
        @Override
        public ResponseHandler<Object> getResponseHandler() {
          return ctx_.getResponseHandler();
        }
        @Override
        public CommonRequestArgs getRequest() {
          return cr;
        }
      };
     
      Class<?>[] pts = serviceMethod.getParameterTypes();
      final Object[] serviceParameters = new Object[pts.length];
      serviceParameters[0] = ctx;
      for (int ii=1; ii<pts.length; ii++) {
        Object par = params.get(ii-1);
        String so = _jsh.serialize(par);
        serviceParameters[ii] = _jsh.deserialize(so, pts[ii]);
      }
      if (serviceMethod.isAnnotationPresent(Transactional.class)) {
        Transactional trx = serviceMethod.getAnnotation(Transactional.class);
        Preconditions.checkNotNull(transactionManager,"The method is transactionnal, but no transaction manager was detected!");
        TransactionTemplate trxTpl = new TransactionTemplate(transactionManager);
        trxTpl.setIsolationLevel(trx.isolation().value());
        trxTpl.setReadOnly(trx.readOnly());
        trxTpl.setPropagationBehavior(trx.propagation().value());
        trxTpl.setTimeout(trx.timeout());
        trxTpl.execute(new TransactionCallbackWithoutResult() {
          @Override
          protected void doInTransactionWithoutResult(TransactionStatus status) {
            try {
              serviceMethod.invoke(cmp.getComponent(), serviceParameters);
            } catch (Throwable e) {
              status.setRollbackOnly();
              if (e instanceof InvocationTargetException) {
                handleException(ctx_, namespace, serviceName, ((InvocationTargetException)e).getTargetException());
              } else {
                handleException(ctx_, namespace, serviceName, e);
              }
            }
          }});
       
      } else {
          serviceMethod.invoke(cmp.getComponent(), serviceParameters);
      }     
     
    } catch (InvocationTargetException e) {
      handleException(ctx_, namespace, serviceName, e.getTargetException());
    } catch (Throwable e) {
      handleException(ctx_, namespace, serviceName, e);
    }
  }

  private void handleException(final Context ctx_, String ns, String serviceName, Throwable e) {
    if (e instanceof ApplicationException) {
      ApplicationException appEx = (ApplicationException)e;
      _logger.warn(String.format("Failed to invoke service e=%s, ns=%s",
          serviceName, ns), appEx);
      for (Message message : appEx.getMessages()) {
        ctx_.getResponseHandler().addMessage(message);
      }
     
    } else {
      _logger.error(String.format("Failed to invoke service=%s, ns=%s",
          serviceName, ns), e);
      ctx_.getResponseHandler().addMessage(CommonMessageID.SERVICE_FAILURE.getMessage());
    }
  }

  public List<ServiceComponent> getComponents() {
    return _components;
  }

  public void setComponents(List<ServiceComponent> components_) {
    _components = components_;
    registerServices(components_);
  }


  @Override
  public void afterPropertiesSet() throws Exception {
    try {
      transactionManager = beanFactory.getBean(PlatformTransactionManager.class);
    } catch (NoSuchBeanDefinitionException e) {
      _logger.warn("No (or more than one) TransactionManager defined in your Spring context. Will not set transaction manager.",e);
    }
  }

  @Override
  public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    this.beanFactory = beanFactory;
   
  }

}
TOP

Related Classes of org.butor.json.service.DefaultServiceManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.