public static RefinedResourceSchema parse(ResourceType resourceType, PrismContext prismContext)
      throws SchemaException {

    ResourceSchema originalResourceSchema = getResourceSchema(resourceType, prismContext);
    if (originalResourceSchema == null) {
      return null;
    }

    String contextDescription = "definition of " + resourceType;

    RefinedResourceSchemaImpl rSchema = new RefinedResourceSchemaImpl(originalResourceSchema);

    SchemaHandlingType schemaHandling = resourceType.getSchemaHandling();
    if (schemaHandling != null) {
      parseObjectTypeDefsFromSchemaHandling(
          rSchema,
          resourceType,
          schemaHandling,
          schemaHandling.getObjectType(),
          null,
          prismContext,
          contextDescription);
    }

    parseObjectTypesFromSchema(rSchema, resourceType, prismContext, contextDescription);

    // We need to parse associations and auxiliary object classes in a second pass. We need to have
    // all object classes parsed before correctly setting association
    // targets
    for (RefinedObjectClassDefinition rOcDef : rSchema.getRefinedDefinitions()) {
      ((RefinedObjectClassDefinitionImpl) rOcDef).parseAssociations(rSchema);
      ((RefinedObjectClassDefinitionImpl) rOcDef).parseAuxiliaryObjectClasses(rSchema);
    }

    // We can parse attributes only after we have all the object class info parsed (including
    // auxiliary object classes)
    for (RefinedObjectClassDefinition rOcDef : rSchema.getRefinedDefinitions()) {
      ((RefinedObjectClassDefinitionImpl) rOcDef).parseAttributes(rSchema, contextDescription);
    }

    return rSchema;
  }
  private static void parseObjectTypesFromSchema(
      RefinedResourceSchemaImpl rSchema,
      ResourceType resourceType,
      PrismContext prismContext,
      String contextDescription)
      throws SchemaException {

    RefinedObjectClassDefinition rAccountDefDefault = null;
    for (ObjectClassComplexTypeDefinition objectClassDef :
        rSchema.getOriginalResourceSchema().getObjectClassDefinitions()) {
      QName objectClassname = objectClassDef.getTypeName();
      if (rSchema.getRefinedDefinition(objectClassname) != null) {
        continue;
      }
      RefinedObjectClassDefinition rOcDef =
          RefinedObjectClassDefinitionImpl.parseFromSchema(
              objectClassDef,
              resourceType,
              rSchema,
              prismContext,
              "object class " + objectClassname + ", in " + contextDescription);

      if (objectClassDef.getKind() == ShadowKindType.ACCOUNT && rOcDef.isDefault()) {
        if (rAccountDefDefault == null) {
          rAccountDefDefault = rOcDef;
        } else {
          throw new SchemaException(
              "More than one default account definitions ("
                  + rAccountDefDefault
                  + ", "
                  + rOcDef
                  + ") in "
                  + contextDescription);
        }
      }

      rSchema.add(rOcDef);
    }
  }
  private static void parseObjectTypeDefsFromSchemaHandling(
      RefinedResourceSchemaImpl rSchema,
      ResourceType resourceType,
      SchemaHandlingType schemaHandling,
      Collection<ResourceObjectTypeDefinitionType> resourceObjectTypeDefs,
      ShadowKindType impliedKind,
      PrismContext prismContext,
      String contextDescription)
      throws SchemaException {

    if (resourceObjectTypeDefs == null) {
      return;
    }

    Map<ShadowKindType, RefinedObjectClassDefinition> defaults = new HashMap<>();

    for (ResourceObjectTypeDefinitionType accountTypeDefType : resourceObjectTypeDefs) {
      RefinedObjectClassDefinition rOcDef =
          RefinedObjectClassDefinitionImpl.parse(
              accountTypeDefType,
              resourceType,
              rSchema,
              impliedKind,
              prismContext,
              contextDescription);

      if (rOcDef.isDefault()) {
        if (defaults.containsKey(rOcDef.getKind())) {
          throw new SchemaException(
              "More than one default "
                  + rOcDef.getKind()
                  + " definitions ("
                  + defaults.get(rOcDef.getKind())
                  + ", "
                  + rOcDef
                  + ") in "
                  + contextDescription);
        } else {
          defaults.put(rOcDef.getKind(), rOcDef);
        }
      }

      rSchema.add(rOcDef);
    }
  }