/**
  * Checks whether any of the signatures among the pairs of the given serializations matches the
  * header of the given byte array, and returns the matching signature/charset pair.
  *
  * @param candidates The serializations.
  * @param data The byte array.
  * @return The matching signature/charset pair, or null if no candidate contains a matching pair.
  *     If more than one signature/charset pair is a match, the one with the longest signature is
  *     returned; and if there is more than one with the same length, the first such match is
  *     returned.
  */
 public static SignatureCharset getPrefixMatch(Serialization[] candidates, byte[] data) {
   EnumSet<Signature> signatures = EnumSet.noneOf(Signature.class);
   for (Serialization serialization : candidates) {
     for (SignatureCharset sc : serialization.getSignatureCharsets()) {
       signatures.add(sc.getSignature());
     }
   }
   Signature match = Signature.getPrefixMatch(signatures.toArray(Signature.EMPTY_ARRAY), data);
   for (Serialization serialization : candidates) {
     for (SignatureCharset sc : serialization.getSignatureCharsets()) {
       if (sc.getSignature() == match) {
         return sc;
       }
     }
   }
   return null;
 }
  private Response put(
      final UserGroupInformation ugi,
      final DelegationParam delegation,
      final UserParam username,
      final DoAsParam doAsUser,
      final String fullpath,
      final PutOpParam op,
      final DestinationParam destination,
      final OwnerParam owner,
      final GroupParam group,
      final PermissionParam permission,
      final OverwriteParam overwrite,
      final BufferSizeParam bufferSize,
      final ReplicationParam replication,
      final BlockSizeParam blockSize,
      final ModificationTimeParam modificationTime,
      final AccessTimeParam accessTime,
      final RenameOptionSetParam renameOptions,
      final CreateParentParam createParent,
      final TokenArgumentParam delegationTokenArgument)
      throws IOException, URISyntaxException {

    final Configuration conf = (Configuration) context.getAttribute(JspHelper.CURRENT_CONF);
    final NameNode namenode = (NameNode) context.getAttribute("name.node");
    final NamenodeProtocols np = namenode.getRpcServer();

    switch (op.getValue()) {
      case CREATE:
        {
          final URI uri =
              redirectURI(
                  namenode,
                  ugi,
                  delegation,
                  username,
                  doAsUser,
                  fullpath,
                  op.getValue(),
                  -1L,
                  blockSize.getValue(conf),
                  permission,
                  overwrite,
                  bufferSize,
                  replication,
                  blockSize);
          return Response.temporaryRedirect(uri).type(MediaType.APPLICATION_OCTET_STREAM).build();
        }
      case MKDIRS:
        {
          final boolean b = np.mkdirs(fullpath, permission.getFsPermission(), true);
          final String js = JsonUtil.toJsonString("boolean", b);
          return Response.ok(js).type(MediaType.APPLICATION_JSON).build();
        }
      case CREATESYMLINK:
        {
          np.createSymlink(
              destination.getValue(),
              fullpath,
              PermissionParam.getDefaultFsPermission(),
              createParent.getValue());
          return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build();
        }
      case RENAME:
        {
          final EnumSet<Options.Rename> s = renameOptions.getValue();
          if (s.isEmpty()) {
            final boolean b = np.rename(fullpath, destination.getValue());
            final String js = JsonUtil.toJsonString("boolean", b);
            return Response.ok(js).type(MediaType.APPLICATION_JSON).build();
          } else {
            np.rename2(fullpath, destination.getValue(), s.toArray(new Options.Rename[s.size()]));
            return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build();
          }
        }
      case SETREPLICATION:
        {
          final boolean b = np.setReplication(fullpath, replication.getValue(conf));
          final String js = JsonUtil.toJsonString("boolean", b);
          return Response.ok(js).type(MediaType.APPLICATION_JSON).build();
        }
      case SETOWNER:
        {
          if (owner.getValue() == null && group.getValue() == null) {
            throw new IllegalArgumentException("Both owner and group are empty.");
          }

          np.setOwner(fullpath, owner.getValue(), group.getValue());
          return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build();
        }
      case SETPERMISSION:
        {
          np.setPermission(fullpath, permission.getFsPermission());
          return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build();
        }
      case SETTIMES:
        {
          np.setTimes(fullpath, modificationTime.getValue(), accessTime.getValue());
          return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build();
        }
      case RENEWDELEGATIONTOKEN:
        {
          final Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>();
          token.decodeFromUrlString(delegationTokenArgument.getValue());
          final long expiryTime = np.renewDelegationToken(token);
          final String js = JsonUtil.toJsonString("long", expiryTime);
          return Response.ok(js).type(MediaType.APPLICATION_JSON).build();
        }
      case CANCELDELEGATIONTOKEN:
        {
          final Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>();
          token.decodeFromUrlString(delegationTokenArgument.getValue());
          np.cancelDelegationToken(token);
          return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build();
        }
      default:
        throw new UnsupportedOperationException(op + " is not supported");
    }
  }
  /**
   * Parses an entity's attribute string to get attribute values
   *
   * @param attributeStringBuilder
   * @param attributeValueType
   * @return a single attribute value or list of attribute values
   * @throws IfcFormatException
   * @throws IfcNotFoundException
   * @throws IfcValueTypeConflictException
   */
  private List<IfcValue> parseAttributeValues(
      StrBuilderWrapper attributeStrBuilderWrapper,
      IfcEntity entity,
      List<IfcAttributeInfo> entityAttributeInfos,
      IfcTypeInfo commonAttributeTypeInfo,
      EnumSet<IfcTypeEnum> commonValueTypes)
      throws IfcFormatException, IfcNotFoundException {

    logger.debug(String.format("Parsing entity '%s'", entity));

    List<IfcValue> attributeValues = new ArrayList<>();

    for (int attributeIndex = 0;
        !attributeStrBuilderWrapper.trimLeft().isEmpty();
        ++attributeIndex) {

      EnumSet<IfcTypeEnum> attributeValueTypes;
      IfcAttributeInfo attributeInfo;
      IfcTypeInfo attributeTypeInfo;
      if (commonValueTypes == null) {
        assert (attributeIndex < entityAttributeInfos.size())
            : String.format(
                "attributeIndex=%d, entityAttributeInfos.size=%s, attributeStrBuilderWrapper='%s'",
                attributeIndex, entityAttributeInfos, attributeStrBuilderWrapper);
        attributeInfo = entityAttributeInfos.get(attributeIndex);
        attributeTypeInfo = attributeInfo.getAttributeTypeInfo();
        attributeValueTypes = attributeTypeInfo.getValueTypes();
      } else {
        assert (commonAttributeTypeInfo != null);
        attributeInfo = entityAttributeInfos.get(0);
        attributeTypeInfo = commonAttributeTypeInfo;
        attributeValueTypes = commonValueTypes;
      }

      if (attributeTypeInfo instanceof IfcCollectionTypeInfo) {
        attributeTypeInfo = ((IfcCollectionTypeInfo) attributeTypeInfo).getItemTypeInfo();
      }

      switch (attributeStrBuilderWrapper.charAt(0)) {
        case IfcVocabulary.StepFormat.LINE_NUMBER_SYMBOL: // Entity
          attributeStrBuilderWrapper.skip(1);
          Long remoteLineNumber = attributeStrBuilderWrapper.getLong();
          IfcEntity remoteEntity = getEntity(remoteLineNumber);
          if (remoteEntity == null) {
            throw new IfcNotFoundException("Entity not found: #" + remoteLineNumber);
          }
          attributeValues.add(remoteEntity);
          break;

        case IfcVocabulary.StepFormat.STRING_VALUE_SYMBOL:
          String s = attributeStrBuilderWrapper.getStringBetweenSingleQuotes();
          assert attributeValueTypes.size() == 1 : "Expect attributeValueTypes.size() == 1";
          //				if (!attributeValueTypes.contains(IfcTypeEnum.GUID)) {
          attributeValues.add(new IfcLiteralValue(s, attributeTypeInfo, IfcTypeEnum.STRING));
          //					break;
          //				} else {
          //					attributeValues.add(new IfcGuidValue(s));
          //					break;
          //				}
          break;

        case IfcVocabulary.StepFormat.ENUMERATION_VALUE_SYMBOL:
          s =
              attributeStrBuilderWrapper.getStringBetweenSimilarCharacters(
                  IfcVocabulary.StepFormat.ENUMERATION_VALUE_SYMBOL);

          assert attributeValueTypes.size() == 1 : "Expect attributeValueTypes.size() == 1";
          if (!attributeValueTypes.contains(IfcTypeEnum.LOGICAL)) {
            attributeValues.add(new IfcLiteralValue(s, attributeTypeInfo, IfcTypeEnum.ENUM));
          } else {
            switch (s) {
              case "T":
              case "TRUE":
                attributeValues.add(
                    new IfcLiteralValue(
                        LogicalEnum.TRUE.toString(), attributeTypeInfo, IfcTypeEnum.LOGICAL));
                break;
              case "F":
              case "FALSE":
                attributeValues.add(
                    new IfcLiteralValue(
                        LogicalEnum.FALSE.toString(), attributeTypeInfo, IfcTypeEnum.LOGICAL));
                break;
              default:
                attributeValues.add(
                    new IfcLiteralValue(
                        LogicalEnum.UNKNOWN.toString(), attributeTypeInfo, IfcTypeEnum.LOGICAL));
                break;
            }
          }
          break;

        case IfcVocabulary.StepFormat.NULL_SYMBOL: // $
          attributeValues.add(IfcValue.NULL);
          attributeStrBuilderWrapper.skip(1);
          break;

        case IfcVocabulary.StepFormat.ANY_SYMBOL: // *
          attributeValues.add(IfcValue.ANY);
          attributeStrBuilderWrapper.skip(1);
          break;

        case StringUtils.OPENING_ROUND_BRACKET_CHAR: // List or Set
          String stringBetweenBrackets = attributeStrBuilderWrapper.getStringBetweenRoundBrackets();

          StrBuilderWrapper sbWrapper = new StrBuilderWrapper(stringBetweenBrackets);

          List<IfcAttributeInfo> attributeInfos = new ArrayList<>(1);
          attributeInfos.add(attributeInfo);

          List<IfcValue> values =
              parseAttributeValues(
                  sbWrapper, null, attributeInfos, attributeTypeInfo, attributeValueTypes);
          attributeValues.add(new IfcTemporaryCollectionValueWrapper(values));
          break;

        default:
          if (Character.isAlphabetic(attributeStrBuilderWrapper.charAt(0))) {

            //
            // parsing sub entity
            //
            String subEntityTypeInfoName = attributeStrBuilderWrapper.getIdentifierName();
            IfcNonEntityTypeInfo subNonEntityTypeInfo =
                schema.getNonEntityTypeInfo(subEntityTypeInfoName);
            attributeValueTypes = subNonEntityTypeInfo.getValueTypes();
            s = attributeStrBuilderWrapper.getStringBetweenRoundBrackets();

            assert (s != null);

            attributeInfos = new ArrayList<>(1);
            attributeInfos.add(attributeInfo);

            values =
                parseAttributeValues(
                    new StrBuilderWrapper(s),
                    null,
                    attributeInfos,
                    subNonEntityTypeInfo,
                    attributeValueTypes);
            assert values.size() == 1
                : "Expect only 1 argument: " + entity + ":" + values.toString();
            // attributeValues.add(new IfcShortEntity(subNonEntityTypeInfo,
            // (IfcLiteralValue)values.get(0)));
            attributeValues.add((IfcLiteralValue) values.get(0));
          } else {

            //
            // parsing number or datetime
            //
            assert attributeValueTypes.size() == 1 : "Expect attributeValueTypes.size() == 1";
            IfcTypeEnum attributeValueType = (IfcTypeEnum) attributeValueTypes.toArray()[0];
            Object value;
            if (attributeValueType == IfcTypeEnum.INTEGER) {
              value = attributeStrBuilderWrapper.getLong();
            } else if (attributeValueType == IfcTypeEnum.REAL) {
              value = attributeStrBuilderWrapper.getDouble();
            } else {
              assert attributeValueType == IfcTypeEnum.DATETIME;
              long timeStamp = attributeStrBuilderWrapper.getLong();
              value = Calendar.getInstance();
              ((Calendar) value).setTimeInMillis(timeStamp * 1000);
            }

            attributeValues.add(
                new IfcLiteralValue(
                    value, (IfcNonEntityTypeInfo) attributeTypeInfo, attributeValueType));
          }

          break;
      }

      attributeStrBuilderWrapper.trimLeft();
      attributeStrBuilderWrapper.getFirstMatch(StrMatcher.commaMatcher());
    }

    return attributeValues;
  }
 public Type randomValueType(EnumSet<Type> typeEnum, Random random) {
   Type[] array = typeEnum.toArray(new Type[0]);
   return array[random.nextInt(array.length)];
 }