All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.v5.amp.stub.TransferAsset Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
 *
 * This file is part of Baratine(TM)
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Baratine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Baratine 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, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Baratine; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Alex Rojkov
 */

package com.caucho.v5.amp.stub;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Objects;

import com.caucho.v5.amp.vault.VaultException;
import com.caucho.v5.convert.bean.FieldBean;
import com.caucho.v5.convert.bean.FieldBeanFactory;
import com.caucho.v5.util.L10N;

import io.baratine.vault.Id;

/**
 * Copies to and from a transfer object.
 */
public class TransferAsset
{
  private static final L10N L = new L10N(TransferAsset.class);
  
  private Class _assetType;
  private Class _transferType;
  
  private FieldCopy []_toAsset;
  private FieldCopy []_toTransfer;

  public TransferAsset(Class beanType,
                       Class transferType)
  {
    Objects.requireNonNull(beanType);
    Objects.requireNonNull(transferType);
    
    _assetType = beanType;
    _transferType = transferType;
    
    introspect();
  }
  
  @SuppressWarnings("unchecked")
  private void introspect()
  {
    validateConstructor();
    
    ArrayList> toAssetList = new ArrayList<>();
    ArrayList> toTransferList = new ArrayList<>();
    
    introspect(_assetType, _transferType, toAssetList, toTransferList);
    
    if (toTransferList.size() == 0) {
      throw error("'{0}' is an invalid transfer object for '{1}' because it has no matching fields",
                  _transferType.getSimpleName(),
                  _assetType.getSimpleName());
    }
    
    _toAsset = new FieldCopy[toAssetList.size()];
    toAssetList.toArray(_toAsset);
    
    _toTransfer = new FieldCopy[toTransferList.size()];
    toTransferList.toArray(_toTransfer);
  }
  
  private void validateConstructor()
  {
    if (Modifier.isAbstract(_transferType.getModifiers())
        && ! _transferType.equals(_assetType)) {
      throw error("'{0}' is an invalid transfer object for '{1}' because it is abstract",
                  _transferType.getSimpleName(),
                  _assetType.getSimpleName());
    }
    
    if (_transferType.isMemberClass() 
        && ! Modifier.isStatic(_transferType.getModifiers())) {
      throw error("'{0}' is an invalid transfer object for '{1}' because it is a non-static inner class",
                  _transferType.getSimpleName(),
                  _assetType.getSimpleName());
    }
  }
  
  private void introspect(Class assetType, 
                          Class transferType,
                          ArrayList> toAssetList,
                          ArrayList> toTransferList)
  {
    if (transferType == null) {
      return;
    }
    
    introspect(assetType,
               transferType.getSuperclass(), 
               toAssetList, 
               toTransferList);
    
    for (Field fieldTransfer : transferType.getDeclaredFields()) {
      if (Modifier.isStatic(fieldTransfer.getModifiers())) {
        continue;
      }
      
      if (Modifier.isTransient(fieldTransfer.getModifiers())) {
        continue;
      }
      
      Field fieldAsset = findField(assetType, fieldTransfer);
      
      if (fieldAsset == null) {
        throw error("Field '{0}' is unknown in asset '{1}' used by transfer object '{2}'",
                    fieldTransfer.getName(),
                    _assetType.getSimpleName(),
                    _transferType.getSimpleName());
      }
      
      FieldBean fieldBeanAsset = FieldBeanFactory.get(fieldAsset);
      FieldBean fieldBeanTransfer = FieldBeanFactory.get(fieldTransfer);
      
      FieldCopy fieldCopy 
        = new FieldCopy<>(fieldBeanAsset, fieldBeanTransfer);
      
      toTransferList.add(fieldCopy);
      
      if (! isId(fieldAsset)) {
        toAssetList.add(fieldCopy);
      }
    }
  }
  
  private boolean isId(Field field)
  {
    if (field.isAnnotationPresent(Id.class)) {
      return true;
    }
    else if (field.getName().equals("id")) {
      return true;
    }
    else if (field.getName().equals("_id")) {
      return true;
    }
    else {
      return false;
    }
  }
  
  private Field findField(Class type, Field fieldTest)
  {
    if (type == null) {
      return null;
    }
    
    for (Field field : type.getDeclaredFields()) {
      if (Modifier.isStatic(field.getModifiers())) {
        continue;
      }
      
      if (Modifier.isTransient(field.getModifiers())) {
        continue;
      }
      
      if (! field.getName().equals(fieldTest.getName())) {
        continue;
      }
      
      if (field.getType().equals(fieldTest.getType())) {
        return field;
      }
      
      throw error("Field '{0}' with type '{1}' in asset '{2}' does not match field in transfer object '{3}' with type '{4}'",
                  field.getName(),
                  field.getType().getSimpleName(),
                  _assetType.getSimpleName(),
                  _transferType.getSimpleName(),
                  fieldTest.getType().getSimpleName());
    }
    
    return findField(type.getSuperclass(), fieldTest);
  }
  
  public void toAsset(T asset, S transfer)
  {
    Objects.requireNonNull(asset);
    Objects.requireNonNull(transfer);
    
    for (FieldCopy fieldCopy : _toAsset) {
      fieldCopy.toAsset(asset, transfer);
    }
  }
  
  public void toTransfer(T asset, S transfer)
  {
    Objects.requireNonNull(asset);
    Objects.requireNonNull(transfer);
    
    for (FieldCopy fieldCopy : _toTransfer) {
      fieldCopy.toTransfer(asset, transfer);
    }
  }
  
  public S toTransfer(T asset)
  {
    try {
      S transfer = (S) _transferType.newInstance();
      
      toTransfer(asset, transfer);
      
      return transfer;
    } catch (Exception e) {
      throw new VaultException(e);
    }
  }
  
  private RuntimeException error(String msg, Object ...args)
  {
    return new VaultException(L.l(msg, args));
  }
  
  @Override
  public String toString()
  {
    return (getClass().getSimpleName()
           + "[" + _assetType.getSimpleName()
           + "," + _transferType.getSimpleName()
           + "]");
  }
  
  private static class FieldCopy
  {
    private FieldBean _fieldAsset;
    private FieldBean _fieldTransfer;
    
    FieldCopy(FieldBean fieldAsset,
              FieldBean fieldTransfer)
    {
      _fieldAsset = fieldAsset;
      _fieldTransfer = fieldTransfer;
    }
    
    public void toAsset(T asset, S transfer)
    {
      _fieldAsset.setObject(asset, _fieldTransfer.getObject(transfer));
    }
    
    public void toTransfer(T asset, S transfer)
    {
      _fieldTransfer.setObject(transfer, _fieldAsset.getObject(asset));
    }
  }
}