/**
   * Return the XMIHeader for the specified File or null if the file does not represent a MetaMatrix
   * model file.
   *
   * @param resource The file of a metamatrix model file.
   * @return The XMIHeader for the model file
   */
  public static XMIHeader getXmiHeader(final File resource) {
    if (resource != null && resource.isFile() && resource.exists() && resource.canRead()) {
      // check cache
      if (CACHE != null) {
        XMIHeader header = CACHE.getCachedXmiHeader(resource);
        if (header != null) {
          return header;
        }
      }
      try {
        XMIHeader header = XMIHeaderReader.readHeader(resource);
        // add to cache
        if (CACHE != null) {
          CACHE.setXmiHeaderToCache(resource, header);
        }
        return header;
      } catch (TeiidException e) {
        LogManager.logWarning(RuntimeMetadataPlugin.PLUGIN_ID, e, e.getMessage());
      } catch (IllegalArgumentException iae) {
        // Swallowing this exception because we're doing all three checks that would produce it.
        // If this exception is caught, it's because the files really were closed/deleted in another
        // thread and this
        // thread didn't know about it.
        // Fixes Defect 22117
      }
    }

    return null;
  }
  // GHH 20080326 - set all batches as last batch after an exception
  // is thrown calling a method on the enumeration.  Per Javadoc for
  // javax.naming.NamingEnumeration, enumeration is invalid after an
  // exception is thrown - by setting last batch indicator we prevent
  // it from being used again.
  // GHH 20080326 - also added return of explanation for generic
  // NamingException
  public List<?> next() throws TranslatorException {
    try {
      if (unwrapIterator != null) {
        if (unwrapIterator.hasNext()) {
          return unwrapIterator.next();
        }
        unwrapIterator = null;
      }
      // The search has been executed, so process up to one batch of
      // results.
      List<?> result = null;
      while (result == null && searchEnumeration != null && searchEnumeration.hasMore()) {
        SearchResult searchResult = (SearchResult) searchEnumeration.next();
        try {
          result = getRow(searchResult);
        } catch (InvalidNameException e) {

        }
      }

      if (result == null && this.executionFactory.usePagination()) {
        byte[] cookie = null;
        Control[] controls = ldapCtx.getResponseControls();
        if (controls != null) {
          for (int i = 0; i < controls.length; i++) {
            if (controls[i] instanceof PagedResultsResponseControl) {
              PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
              cookie = prrc.getCookie();
            }
          }
        }

        if (cookie == null) {
          return null;
        }

        setRequestControls(cookie);
        executeSearch();
        return next();
      }

      if (result != null) {
        resultCount++;
      }
      return result;
    } catch (SizeLimitExceededException e) {
      if (resultCount != searchDetails.getCountLimit()) {
        String msg = LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12008);
        TranslatorException te = new TranslatorException(e, msg);
        if (executionFactory.isExceptionOnSizeLimitExceeded()) {
          throw te;
        }
        this.executionContext.addWarning(te);
        LogManager.logWarning(LogConstants.CTX_CONNECTOR, e, msg);
      }
      return null; // GHH 20080326 - if size limit exceeded don't try to read more results
    } catch (NamingException ne) {
      throw new TranslatorException(ne, LDAPPlugin.Util.gs("ldap_error")); // $NON-NLS-1$
    }
  }
 /**
  * Return the XMIHeader for the specified inputstream of a model file.
  *
  * @param resourceStream The inputStream of a metamatrix model file.
  * @return The XMIHeader for the model file
  */
 public static XMIHeader getXmiHeader(final InputStream resourceStream) {
   if (resourceStream != null) {
     try {
       return XMIHeaderReader.readHeader(resourceStream);
     } catch (TeiidException e) {
       LogManager.logWarning(RuntimeMetadataPlugin.PLUGIN_ID, e, e.getMessage());
     }
   }
   return null;
 }
 // GHH 20080326 - replaced existing implementation with the same
 // code as used by cancel method.  First try to
 // close the searchEnumeration, then the search context
 // We are very conservative when closing the enumeration
 // but less so when closing context, since it is safe to call close
 // on contexts multiple times
 @Override
 public void close() {
   if (searchEnumeration != null) {
     try {
       searchEnumeration.close();
     } catch (Exception e) {
     } // catch everything, because NamingEnumeration has undefined behavior if it previously hit
       // an exception
   }
   if (ldapCtx != null) {
     try {
       ldapCtx.close();
     } catch (NamingException ne) {
       LogManager.logWarning(
           LogConstants.CTX_CONNECTOR,
           LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12003, ne.getExplanation()));
     }
   }
 }
  // GHH 20080326 - added resultDistinguishedName to method signature.  If
  // there is an element in the model named "DN" and there is no attribute
  // with this name in the search result, we return this new parameter
  // value for that column in the result
  // GHH 20080326 - added handling of ClassCastException when non-string
  // attribute is returned
  private Object getValue(
      Column modelElement, SearchResult result, Attributes attrs, boolean unwrap)
      throws TranslatorException, InvalidNameException {

    String modelAttrName = modelElement.getSourceName();
    Class<?> modelAttrClass = modelElement.getJavaType();

    String multivalAttr = modelElement.getDefaultValue();

    if (modelAttrName == null) {
      final String msg =
          LDAPPlugin.Util.getString("LDAPSyncQueryExecution.nullAttrError"); // $NON-NLS-1$
      throw new TranslatorException(msg);
    }

    Attribute resultAttr = attrs.get(modelAttrName);

    // If the attribute is not present, we return NULL.
    if (resultAttr == null) {
      // GHH 20080326 - return DN from input parameter
      // if DN attribute is not present in search result
      if (modelAttrName.equalsIgnoreCase("DN")) { // $NON-NLS-1$
        return result.getNameInNamespace();
      }
      return null;
    }
    Object objResult = null;
    try {
      if (TypeFacility.RUNTIME_TYPES.STRING.equals(modelAttrClass)
          && MULTIVALUED_CONCAT.equalsIgnoreCase(multivalAttr)) {
        // mpw 5/09
        // Order the multi-valued attrs alphabetically before creating a single string,
        // using the delimiter to separate each token
        ArrayList<String> multivalList = new ArrayList<String>();
        NamingEnumeration<?> attrNE = resultAttr.getAll();
        int length = 0;
        while (attrNE.hasMore()) {
          String val = (String) attrNE.next();
          multivalList.add(val);
          length += ((val == null ? 0 : val.length()) + 1);
        }
        Collections.sort(multivalList);

        StringBuilder multivalSB = new StringBuilder(length);
        Iterator<String> itr = multivalList.iterator();
        while (itr.hasNext()) {
          multivalSB.append(itr.next());
          if (itr.hasNext()) {
            multivalSB.append(delimiter);
          }
        }
        return multivalSB.toString();
      }
      if (modelAttrClass.isArray()) {
        return getArray(modelAttrClass.getComponentType(), resultAttr, modelElement, modelAttrName);
      }
      if (unwrap && resultAttr.size() > 1) {
        return getArray(modelAttrClass, resultAttr, modelElement, modelAttrName);
      }

      // just a single value
      objResult = resultAttr.get();
    } catch (NamingException ne) {
      final String msg =
          LDAPPlugin.Util.gs(LDAPPlugin.Event.TEIID12004, modelAttrName)
              + " : "
              + ne.getExplanation(); // $NON-NLS-1$m
      LogManager.logWarning(LogConstants.CTX_CONNECTOR, msg);
      throw new TranslatorException(ne, msg);
    }

    return convertSingleValue(modelElement, modelAttrName, modelAttrClass, objResult);
  }
  @Override
  public String getSourceComment(ExecutionContext context, Command command) {
    String comment = super.getSourceComment(context, command);

    boolean usingPayloadComment = false;
    if (context != null) {
      // Check for db hints
      Object payload = context.getCommandPayload();
      if (payload instanceof String) {
        String payloadString = (String) payload;
        if (payloadString.startsWith(HINT_PREFIX)) {
          int i = payloadString.indexOf(HINT_SUFFIX);
          if (i > 0 && payloadString.substring(i + 2).trim().length() == 0) {
            comment += payloadString + " "; // $NON-NLS-1$
            usingPayloadComment = true;
          } else {
            String msg =
                JDBCPlugin.Util.gs(
                    JDBCPlugin.Event.TEIID11003, "Execution Payload", payloadString); // $NON-NLS-1$
            context.addWarning(new TranslatorException(msg));
            LogManager.logWarning(LogConstants.CTX_CONNECTOR, msg);
          }
        }
      }
    }

    if (!usingPayloadComment && context != null) {
      String hint = context.getSourceHint();
      if (context.getGeneralHint() != null) {
        if (hint != null) {
          hint += (" " + context.getGeneralHint()); // $NON-NLS-1$
        } else {
          hint = context.getGeneralHint();
        }
      }
      if (hint != null) {
        // append a source hint
        if (!hint.contains(HINT_PREFIX)) {
          comment += HINT_PREFIX + ' ' + hint + ' ' + HINT_SUFFIX + ' ';
        } else {
          String msg =
              JDBCPlugin.Util.gs(JDBCPlugin.Event.TEIID11003, "Source Hint", hint); // $NON-NLS-1$
          context.addWarning(new TranslatorException(msg));
          LogManager.logWarning(LogConstants.CTX_CONNECTOR, msg);
        }
      }
    }

    if (command instanceof Select) {
      //
      // This simple algorithm determines the hint which will be added to the
      // query.
      // Right now, we look through all functions passed in the query
      // (returned as a collection)
      // Then we check if any of those functions are sdo_relate
      // If so, the ORDERED hint is added, if not, it isn't
      Collection<Function> col = CollectorVisitor.collectObjects(Function.class, command);
      for (Function func : col) {
        if (func.getName().equalsIgnoreCase(OracleExecutionFactory.RELATE)) {
          return comment + "/*+ ORDERED */ "; // $NON-NLS-1$
        }
      }
    }
    return comment;
  }