/**
   * @param permId instrument perm id
   * @param attributeEnum instrument attribute enumeration
   * @param effectiveFrom effective from
   * @param effectiveTo effective to
   * @return instrumentVO with the history of the required attribute within the specified period;
   *     return valid object with no attributes if no data found
   * @throws JSONException
   * @throws InvalidRawValueException
   * @throws InvalidServiceMethodCallException
   */
  public InstrumentVO getHistoryAttributeOfInstrumentByPermId(
      Long permId,
      InstrumentVO.AttributesEnum attributeEnum, //
      Date effectiveFrom,
      Date effectiveTo)
      throws JSONException, InvalidRawValueException, InvalidServiceMethodCallException {
    String entityVOStr =
        (String)
            Utils.callMethod( //
                this.getIQMNonTemporalAppModuleService(), //
                "getHistoryEntityVOJSONByAttributeNameAndDateRange", //
                new Object[] {
                  InstrumentVO.entityLevel,
                  permId.toString(),
                  attributeEnum.getEnumName(),
                  Utils.convertToString(effectiveFrom),
                  Utils.convertToString(effectiveTo)
                });

    InstrumentVO instrumentVO = (InstrumentVO) Utils.getEntityVOFromJSON(entityVOStr);
    if (instrumentVO != null) {
      instrumentVO.setIsNormalized(null);
      AttributeConverter.convertEntityVO(instrumentVO, false);
    }
    return instrumentVO;
  }
  /**
   * @param properties - service properties
   * @throws InvalidRMIServiceException <br>
   *     If null properties provided, default properties will be used. <br>
   *     If non-null properties provided, only three properties will be used for RMI calls: <br>
   *     a) Context.SECURITY_PRINCIPAL <br>
   *     b) Context.PROVIDER_URL <br>
   *     c) Context.SECURITY_CREDENTIALS <br>
   *     If any of them missing in the input, the corresponding default properties will be used.
   *     <br>
   *     If the input properties are NOT sufficient for initializing a service, return null. <br>
   */
  public RMIIQMAppModuleServices(Properties properties) throws InvalidRMIServiceException {
    super();
    //        Utils.printTrace(false);
    //        Utils.printMessage("start ... " + Utils.convertToString(new java.util.Date()));

    // collect the configured properties and default properties
    Properties tmpProps = RMIIQMAppModuleServicesConstants.getDefaultProperties();
    if (properties != null) {
      if (properties.containsKey(Context.SECURITY_PRINCIPAL)) {
        tmpProps.setProperty( //
            Context.SECURITY_PRINCIPAL, //
            properties.getProperty(Context.SECURITY_PRINCIPAL));
      }
      if (properties.containsKey(Context.PROVIDER_URL)) {
        tmpProps.setProperty( //
            Context.PROVIDER_URL, //
            properties.getProperty(Context.PROVIDER_URL));
      }
      if (properties.containsKey(Context.SECURITY_CREDENTIALS)) {
        tmpProps.setProperty( //
            Context.SECURITY_CREDENTIALS, //
            properties.getProperty(Context.SECURITY_CREDENTIALS));
      }
    }
    if (!this.validateJNDIProperties(tmpProps)) {
      Utils.printTrace(false);
      Utils.printMessage("!!!!! invalid properties for JNDI initialization !!!!!");
      Utils.printMessage(tmpProps.toString());
      //            tmpProps.list(System.out);
      // TODO , question: is it right to exit here, instead of throwing exceptions?
      return;
    } else {
      appServiceProperties = tmpProps;
      //            if (appServiceProperties.containsKey("print.service.properties")
      //                &&
      // appServiceProperties.get("print.service.properties").toString().equalsIgnoreCase("Y")) {
      //                Utils.printMessage(appServiceProperties.toString());
      ////                appServiceProperties.list(System.out);
      //            }
    }
    try {
      initJNDI(appServiceProperties);
      //            CurrencyLookupVO.set(this.getCurrencyLookup());
      //            MarketLookupVO.set(this.getMarketLookup());
      //            ModelMetadataLookupVO.set(this.getModelMetadataLookup());
      AttributeConverter.init(this);
    } catch (NamingException e) {
      throw new InvalidRMIServiceException(e);
    } catch (InvalidServiceMethodCallException | JSONException ex) {
      throw new InvalidRMIServiceException(ex);
    }
  }
  /**
   * No properties will be accepted, even the default ones This constructor will provide local
   * services instead of remote calling
   *
   * @param userName weblogic-user
   * @param pwd weblogic-pwd
   * @throws com.tr.rdss.generic.model.iqm.concordance.util.InvalidRMIServiceException
   */
  public RMIIQMAppModuleServices(String userName, String pwd) throws InvalidRMIServiceException {
    Properties property = new Properties();

    property.put(Context.SECURITY_PRINCIPAL, userName);
    property.put(Context.SECURITY_CREDENTIALS, pwd);

    try {
      initJNDI(appServiceProperties);
      AttributeConverter.init(this);
    } catch (NamingException e) {
      throw new InvalidRMIServiceException(e);
    } catch (InvalidServiceMethodCallException | JSONException ex) {
      throw new InvalidRMIServiceException(ex);
    }
  }
  /**
   * @param permId quote perm id
   * @param attributeEnum quote attribute enumeration
   * @return quoteVO with the full history of the required attribute; return valid object with no
   *     attributes if no data found
   * @throws JSONException
   * @throws InvalidRawValueException
   * @throws InvalidServiceMethodCallException
   */
  public QuoteVO getHistoryAttributeOfQuoteByPermId(
      Long permId, //
      QuoteVO.AttributesEnum attributeEnum)
      throws JSONException, InvalidRawValueException, InvalidServiceMethodCallException {
    String entityVOStr =
        (String)
            Utils.callMethod( //
                this.getIQMNonTemporalAppModuleService(), //
                "getHistoryEntityVOJSONByAttributeName", //
                new Object[] {QuoteVO.entityLevel, permId.toString(), attributeEnum.getEnumName()});

    QuoteVO quoteVO = (QuoteVO) Utils.getEntityVOFromJSON(entityVOStr);
    if (quoteVO != null) {
      quoteVO.setIsNormalized(null);
      AttributeConverter.convertEntityVO(quoteVO, false);
    }
    return quoteVO;
  }
  /**
   * @param permId quote perm id
   * @param effectiveFromDate effective from
   * @param effectiveToDate effective to
   * @return QuoteVO with all the info of the requested quote
   * @throws JSONException
   * @throws InvalidRawValueException
   * @throws InvalidServiceMethodCallException <br>
   *     Only its BASE_ASEET instrument will have full info provided, while other related issues (if
   *     any) will just have perm ids). <br>
   *     All attributes will have denormalized values instead of ids. <br>
   *     E.g. "Published" (TRCS name) will be provided for ADMIN_STATUS instead of 1010003 (TRCS
   *     perm id).
   */
  public QuoteVO getQuoteVOByPermId(Long permId, Date effectiveFromDate, Date effectiveToDate)
      throws JSONException, InvalidRawValueException, InvalidServiceMethodCallException {

    String entityVOStr =
        (String)
            Utils.callMethod(
                this.getIQMAppService(), //
                "getQuoteVOJSONByPermId", //
                new Object[] { //
                  permId.toString(), //
                  Utils.convertToString(effectiveFromDate), //
                  Utils.convertToString(effectiveToDate) //
                });

    QuoteVO entityVO = (QuoteVO) Utils.getEntityVOFromJSON(entityVOStr);
    if (entityVO != null) {
      entityVO.setIsNormalized(null);
      AttributeConverter.convertEntityVO(entityVO, false);
    }

    return entityVO;
  }
  /**
   * @param entityVO entityVO which holds the business changes
   * @return entity perm id
   * @throws InvalidEntityVOException
   * @throws JSONException
   * @throws InvalidRawValueException
   * @throws InvalidServiceMethodCallException <br>
   *     It calls entityMaintain to save the change to db. <br>
   *     If the db write succeeds, return quote perm id; else throw InvalidEntityVOException.
   */
  public Long saveEntityVO(EntityVO entityVO)
      throws InvalidEntityVOException, JSONException, InvalidRawValueException,
          InvalidServiceMethodCallException {
    ObjectMapper mapper = new ObjectMapper();
    String assetStr = null;
    if (entityVO == null) {
      return null;
    }

    EntityVO tmpEntityVO = AttributeConverter.convertEntityVO(entityVO, true);
    try {
      assetStr = mapper.writeValueAsString((Asset) (tmpEntityVO.getEntity()));

      //            // output for testing
      //            Utils.printTrace(false);
      //            Utils.printMessage(assetStr);
    } catch (IOException ex) {
      //            Utils.printTrace(ex);
      //            Utils.printMessage(ex);
      throw new InvalidEntityVOException(ex);
    }

    String entityMaintainStr =
        (String)
            Utils.callMethod( //
                this.getIQMAppService(), //
                "entityMaintain", //
                new Object[] {assetStr});

    DaoResult daoResult = Utils.fromJSON(entityMaintainStr);

    if (daoResult.isSucc()) {
      return Long.parseLong(daoResult.getKey_value());
    } else {
      throw new InvalidEntityVOException(daoResult.getMessage(), entityMaintainStr);
    }
  }