public MetadataItem get(String metadataIdentificationString) {
    ProjectMetadata projectMetadata = projectOperations.getProjectMetadata();
    if (projectMetadata == null) {
      return null;
    }

    ClassOrInterfaceTypeDetails proxy = getGovernor(metadataIdentificationString);
    if (proxy == null) {
      return null;
    }

    AnnotationMetadata proxyAnnotation =
        GwtUtils.getFirstAnnotation(proxy, GwtUtils.PROXY_ANNOTATIONS);
    if (proxyAnnotation == null) {
      return null;
    }

    String locatorType = GwtUtils.getStringValue(proxyAnnotation.getAttribute("locator"));
    if (!StringUtils.hasText(locatorType)) {
      return null;
    }

    ClassOrInterfaceTypeDetails entity = gwtTypeService.lookupEntityFromProxy(proxy);
    if (entity == null) {
      return null;
    }

    MethodMetadata idAccessor = persistenceMemberLocator.getIdentifierAccessor(entity.getName());
    MethodMetadata versionAccessor = persistenceMemberLocator.getVersionAccessor(entity.getName());
    if (idAccessor == null || versionAccessor == null) {
      return null;
    }

    final JavaType idType = GwtUtils.convertPrimitiveType(idAccessor.getReturnType(), true);
    String locatorIdentifier = PhysicalTypeIdentifier.createIdentifier(new JavaType(locatorType));
    ClassOrInterfaceTypeDetailsBuilder locatorBuilder =
        new ClassOrInterfaceTypeDetailsBuilder(locatorIdentifier);
    AnnotationMetadataBuilder annotationMetadataBuilder =
        new AnnotationMetadataBuilder(RooJavaType.ROO_GWT_LOCATOR);
    annotationMetadataBuilder.addStringAttribute(
        "value", entity.getName().getFullyQualifiedTypeName());
    locatorBuilder.addAnnotation(annotationMetadataBuilder);
    annotationMetadataBuilder = new AnnotationMetadataBuilder(SpringJavaType.COMPONENT);
    locatorBuilder.addAnnotation(annotationMetadataBuilder);
    locatorBuilder.setName(new JavaType(locatorType));
    locatorBuilder.setModifier(Modifier.PUBLIC);
    locatorBuilder.setPhysicalTypeCategory(PhysicalTypeCategory.CLASS);
    locatorBuilder.addExtendsTypes(
        new JavaType(
            GwtUtils.LOCATOR.getFullyQualifiedTypeName(),
            0,
            DataType.TYPE,
            null,
            Arrays.asList(entity.getName(), idType)));
    locatorBuilder.addMethod(getCreateMethod(locatorIdentifier, entity.getName()));
    locatorBuilder.addMethod(
        getFindMethod(locatorBuilder, locatorIdentifier, entity.getName(), idType));
    locatorBuilder.addMethod(getDomainTypeMethod(locatorIdentifier, entity.getName()));
    locatorBuilder.addMethod(getIdMethod(locatorIdentifier, entity.getName(), idAccessor));
    locatorBuilder.addMethod(getIdTypeMethod(locatorIdentifier, entity.getName(), idType));
    locatorBuilder.addMethod(
        getVersionMethod(locatorIdentifier, entity.getName(), versionAccessor));

    typeManagementService.createOrUpdateTypeOnDisk(locatorBuilder.build());
    return null;
  }
  public void notify(String upstreamDependency, String downstreamDependency) {
    ProjectMetadata projectMetadata = projectOperations.getProjectMetadata();
    if (projectMetadata == null) {
      return;
    }

    if (MetadataIdentificationUtils.isIdentifyingClass(downstreamDependency)) {
      Assert.isTrue(
          MetadataIdentificationUtils.getMetadataClass(upstreamDependency)
              .equals(
                  MetadataIdentificationUtils.getMetadataClass(
                      PhysicalTypeIdentifier.getMetadataIdentiferType())),
          "Expected class-level notifications only for PhysicalTypeIdentifier (not '"
              + upstreamDependency
              + "')");

      ClassOrInterfaceTypeDetails cid =
          typeLocationService.getTypeForIdentifier(upstreamDependency);
      boolean processed = false;
      if (MemberFindingUtils.getAnnotationOfType(cid.getAnnotations(), RooJavaType.ROO_GWT_REQUEST)
          != null) {
        ClassOrInterfaceTypeDetails proxy = gwtTypeService.lookupProxyFromRequest(cid);
        if (proxy != null) {
          JavaType typeName = PhysicalTypeIdentifier.getJavaType(proxy.getDeclaredByMetadataId());
          Path typePath = PhysicalTypeIdentifier.getPath(proxy.getDeclaredByMetadataId());
          downstreamDependency = GwtLocatorMetadata.createIdentifier(typeName, typePath);
          processed = true;
        }
      }
      if (!processed
          && MemberFindingUtils.getAnnotationOfType(cid.getAnnotations(), RooJavaType.ROO_GWT_PROXY)
              == null) {
        boolean found = false;
        for (ClassOrInterfaceTypeDetails classOrInterfaceTypeDetails :
            typeLocationService.findClassesOrInterfaceDetailsWithAnnotation(
                RooJavaType.ROO_GWT_PROXY)) {
          AnnotationMetadata annotationMetadata =
              GwtUtils.getFirstAnnotation(
                  classOrInterfaceTypeDetails, GwtUtils.ROO_PROXY_REQUEST_ANNOTATIONS);
          if (annotationMetadata != null) {
            AnnotationAttributeValue<?> attributeValue = annotationMetadata.getAttribute("value");
            if (attributeValue != null) {
              String mirrorName = GwtUtils.getStringValue(attributeValue);
              if (mirrorName != null
                  && cid.getName().getFullyQualifiedTypeName().equals(attributeValue.getValue())) {
                found = true;
                JavaType typeName =
                    PhysicalTypeIdentifier.getJavaType(
                        classOrInterfaceTypeDetails.getDeclaredByMetadataId());
                Path typePath =
                    PhysicalTypeIdentifier.getPath(
                        classOrInterfaceTypeDetails.getDeclaredByMetadataId());
                downstreamDependency = GwtLocatorMetadata.createIdentifier(typeName, typePath);
                break;
              }
            }
          }
        }
        if (!found) {
          return;
        }
      } else if (!processed) {
        // A physical Java type has changed, and determine what the corresponding local metadata
        // identification string would have been
        JavaType typeName = PhysicalTypeIdentifier.getJavaType(upstreamDependency);
        Path typePath = PhysicalTypeIdentifier.getPath(upstreamDependency);
        downstreamDependency = GwtLocatorMetadata.createIdentifier(typeName, typePath);
      }

      // We only need to proceed if the downstream dependency relationship is not already registered
      // (if it's already registered, the event will be delivered directly later on)
      if (metadataDependencyRegistry
          .getDownstream(upstreamDependency)
          .contains(downstreamDependency)) {
        return;
      }
    }

    // We should now have an instance-specific "downstream dependency" that can be processed by this
    // class
    Assert.isTrue(
        MetadataIdentificationUtils.getMetadataClass(downstreamDependency)
            .equals(MetadataIdentificationUtils.getMetadataClass(getProvidesType())),
        "Unexpected downstream notification for '"
            + downstreamDependency
            + "' to this provider (which uses '"
            + getProvidesType()
            + "'");

    metadataService.get(downstreamDependency, true);
  }