LayerInfo createLayer(ResourceInfo r, String name, NamespaceInfo ns) {
    String lId = newId();
    StyleInfo s = styles.peekLast();

    final LayerInfo l = createNiceMock(LayerInfo.class);
    layers.add(l);

    expect(l.getId()).andReturn(lId).anyTimes();
    expect(l.getName()).andReturn(name).anyTimes();
    expect(l.getType()).andReturn(LayerInfo.Type.VECTOR).anyTimes();
    expect(l.getResource()).andReturn(r).anyTimes();
    expect(l.getDefaultStyle()).andReturn(s).anyTimes();
    expect(l.isEnabled()).andReturn(true).anyTimes();
    expect(l.isAdvertised()).andReturn(true).anyTimes();

    expect(catalog.getLayer(lId)).andReturn(l).anyTimes();
    expect(catalog.getLayerByName(name)).andReturn(l).anyTimes();
    expect(catalog.getLayerByName(ns.getPrefix() + ":" + name)).andReturn(l).anyTimes();
    expect(catalog.getLayerByName(new NameImpl(ns.getPrefix(), name))).andReturn(l).anyTimes();
    expect(catalog.getLayerByName(new NameImpl(ns.getURI(), name))).andReturn(l).anyTimes();
    expect(catalog.getLayers(r)).andReturn(Arrays.asList(l)).anyTimes();
    l.accept((CatalogVisitor) anyObject());
    expectLastCall()
        .andAnswer(
            new VisitAnswer() {
              @Override
              protected void doVisit(CatalogVisitor visitor) {
                visitor.visit(l);
              }
            })
        .anyTimes();

    callback.onLayer(name, l, this);
    return l;
  }
  public MockCatalogBuilder dataStore(String name) {
    String dsId = newId();
    final WorkspaceInfo ws = workspaces.peekLast();
    final NamespaceInfo ns = namespaces.peekLast();

    final DataStoreInfo ds = createNiceMock(DataStoreInfo.class);
    dataStores.add(ds);

    initStore(ds, DataStoreInfo.class, dsId, name, ws);

    // setup the property data store
    final File propDir = new File(dataDirRoot, name);

    HashMap cxParams = new HashMap();
    cxParams.put(PropertyDataStoreFactory.DIRECTORY.key, propDir);
    cxParams.put(PropertyDataStoreFactory.NAMESPACE.key, ns.getURI());
    expect(ds.getConnectionParameters()).andReturn(cxParams).anyTimes();

    try {
      expect(ds.getDataStore(null))
          .andAnswer(
              (IAnswer)
                  new IAnswer<DataAccess>() {
                    @Override
                    public DataAccess answer() throws Throwable {
                      return new PropertyDataStore(propDir, ns.getURI());
                    }
                  })
          .anyTimes();
    } catch (IOException e) {
    }

    expect(catalog.getDataStore(dsId)).andReturn(ds).anyTimes();
    expect(catalog.getDataStoreByName(name)).andReturn(ds).anyTimes();
    expect(catalog.getDataStoreByName(ws.getName(), name)).andReturn(ds).anyTimes();
    expect(catalog.getDataStoreByName(ws, name)).andReturn(ds).anyTimes();

    ds.accept((CatalogVisitor) anyObject());
    expectLastCall()
        .andAnswer(
            new VisitAnswer() {
              @Override
              protected void doVisit(CatalogVisitor visitor) {
                visitor.visit(ds);
              }
            })
        .anyTimes();

    callback.onStore(name, ds, ws, this);
    replay(ds);
    return this;
  }
  public void visit(WorkspaceInfo workspace) {
    // remove owned stores
    for (StoreInfo s : catalog.getStoresByWorkspace(workspace, StoreInfo.class)) {
      s.accept(this);
    }

    // remove any linked namespaces
    NamespaceInfo ns = catalog.getNamespaceByPrefix(workspace.getName());
    if (ns != null) {
      ns.accept(this);
    }

    catalog.remove(workspace);
  }
  @Test
  public void testWorkspaceRemoveAndReadd() {
    // remove all workspaces
    Catalog catalog = getCatalog();
    NamespaceInfo defaultNamespace = catalog.getDefaultNamespace();
    WorkspaceInfo defaultWs = catalog.getDefaultWorkspace();
    List<WorkspaceInfo> workspaces = catalog.getWorkspaces();
    CascadeDeleteVisitor visitor = new CascadeDeleteVisitor(catalog);
    for (WorkspaceInfo ws : workspaces) {
      visitor.visit(ws);
    }
    assertEquals(0, catalog.getWorkspaces().size());
    assertEquals(0, catalog.getNamespaces().size());

    // add back one (this would NPE)
    catalog.add(defaultNamespace);
    catalog.add(defaultWs);
    assertEquals(1, catalog.getWorkspaces().size());
    assertEquals(1, catalog.getNamespaces().size());

    // get back by name (this would NPE too)
    assertNotNull(catalog.getNamespaceByURI(defaultNamespace.getURI()));
  }
  /** Checks that the namespace/workspace listener keeps on working after a catalog reload */
  @Test
  public void testNamespaceWorkspaceListenerAttached() throws Exception {
    Catalog catalog = getCatalog();

    NamespaceInfo ns = catalog.getNamespaceByPrefix(MockData.CITE_PREFIX);
    String newName = "XYWZ1234";
    ns.setPrefix(newName);
    catalog.save(ns);
    assertNotNull(catalog.getWorkspaceByName(newName));
    assertNotNull(catalog.getNamespaceByPrefix(newName));

    // force a reload
    int listenersBefore = catalog.getListeners().size();
    getGeoServer().reload();
    int listenersAfter = catalog.getListeners().size();
    assertEquals(listenersBefore, listenersAfter);

    // check the NamespaceWorkspaceListener is still attached and working
    ns = catalog.getNamespaceByPrefix(newName);
    ns.setPrefix(MockData.CITE_PREFIX);
    catalog.save(ns);
    assertNotNull(catalog.getWorkspaceByName(MockData.CITE_PREFIX));

    // make sure we only have one resource pool listener and one catalog persister
    int countCleaner = 0;
    int countPersister = 0;
    for (CatalogListener listener : catalog.getListeners()) {
      if (listener instanceof ResourcePool.CacheClearingListener) {
        countCleaner++;
      } else if (listener instanceof GeoServerPersister) {
        countPersister++;
      }
    }
    assertEquals(1, countCleaner);
    assertEquals(1, countPersister);
  }
  public MockCatalogBuilder workspace(String name, String uri) {
    String wsId = newId();
    String nsId = newId();

    final WorkspaceInfo ws = createNiceMock(WorkspaceInfo.class);
    workspaces.add(ws);
    expect(ws.getId()).andReturn(wsId).anyTimes();
    expect(ws.getName()).andReturn(name).anyTimes();
    expect(ws.getMetadata()).andReturn(new MetadataMap()).anyTimes();

    expect(catalog.getWorkspace(wsId)).andReturn(ws).anyTimes();
    expect(catalog.getWorkspaceByName(name)).andReturn(ws).anyTimes();

    final NamespaceInfo ns = createNiceMock(NamespaceInfo.class);
    namespaces.add(ns);

    expect(ns.getId()).andReturn(nsId).anyTimes();
    expect(ns.getName()).andReturn(name).anyTimes();
    expect(ns.getPrefix()).andReturn(name).anyTimes();
    expect(ns.getMetadata()).andReturn(new MetadataMap()).anyTimes();

    expect(catalog.getNamespace(nsId)).andReturn(ns).anyTimes();
    expect(catalog.getNamespaceByPrefix(name)).andReturn(ns).anyTimes();
    expect(catalog.getNamespaceByURI(uri)).andReturn(ns).anyTimes();

    ws.accept((CatalogVisitor) anyObject());
    expectLastCall()
        .andAnswer(
            new VisitAnswer() {
              @Override
              protected void doVisit(CatalogVisitor visitor) {
                visitor.visit(ws);
              }
            })
        .anyTimes();

    ns.accept((CatalogVisitor) anyObject());
    expectLastCall()
        .andAnswer(
            new VisitAnswer() {
              @Override
              protected void doVisit(CatalogVisitor visitor) {
                visitor.visit(ns);
              }
            })
        .anyTimes();

    callback.onWorkspace(name, ws, this);

    replay(ws, ns);
    return this;
  }
  /**
   * Process an XmlSchema. This involves creating a NamespaceInfo instance and populating it based
   * on the given XmlSchema.
   *
   * @param xmlBindings
   * @param packageName
   * @see NamespaceInfo
   * @see AnnotationsProcessor
   * @return newly created namespace info, or null if schema is null
   */
  private NamespaceInfo processXmlSchema(XmlBindings xmlBindings, String packageName) {
    XmlSchema schema = xmlBindings.getXmlSchema();
    if (schema == null) {
      return null;
    }
    // create NamespaceInfo
    NamespaceInfo nsInfo = new NamespaceInfo();
    // process XmlSchema
    XmlNsForm form = schema.getAttributeFormDefault();
    nsInfo.setAttributeFormQualified(form.equals(form.QUALIFIED));
    form = schema.getElementFormDefault();
    nsInfo.setElementFormQualified(form.equals(form.QUALIFIED));

    // make sure defaults are set, not null
    nsInfo.setLocation(schema.getLocation() == null ? "##generate" : schema.getLocation());
    nsInfo.setNamespace(schema.getNamespace() == null ? "" : schema.getNamespace());
    NamespaceResolver nsr = new NamespaceResolver();
    // process XmlNs
    for (XmlNs xmlns : schema.getXmlNs()) {
      nsr.put(xmlns.getPrefix(), xmlns.getNamespaceUri());
    }
    nsInfo.setNamespaceResolver(nsr);
    return nsInfo;
  }
  <T extends ResourceInfo> void initResource(
      T r,
      Class<T> clazz,
      String rId,
      String name,
      StoreInfo s,
      NamespaceInfo ns,
      String srs,
      ProjectionPolicy projPolicy,
      ReferencedEnvelope envelope,
      ReferencedEnvelope latLonEnvelope) {

    expect(r.getId()).andReturn(rId).anyTimes();
    expect(r.getName()).andReturn(name).anyTimes();
    expect(r.getQualifiedName()).andReturn(new NameImpl(ns.getURI(), name)).anyTimes();
    expect(r.getNativeName()).andReturn(name).anyTimes();
    expect(r.getQualifiedNativeName()).andReturn(new NameImpl(ns.getURI(), name)).anyTimes();
    expect(r.getTitle()).andReturn(name).anyTimes();
    expect(r.getAbstract()).andReturn("abstract about " + name).anyTimes();
    expect(r.getStore()).andReturn(s).anyTimes();
    expect(r.getNamespace()).andReturn(ns).anyTimes();

    srs = srs != null ? srs : "EPSG:4326";
    expect(r.getSRS()).andReturn(srs).anyTimes();
    try {
      expect(r.getNativeCRS()).andReturn(CRS.decode(srs));
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    expect(r.getKeywords()).andReturn((List) Arrays.asList(new Keyword(name))).anyTimes();
    expect(r.isEnabled()).andReturn(true).anyTimes();
    expect(r.isAdvertised()).andReturn(true).anyTimes();
    expect(r.getProjectionPolicy()).andReturn(projPolicy).anyTimes();
    expect(r.getLatLonBoundingBox()).andReturn(latLonEnvelope).anyTimes();
    ;
    expect(r.getNativeBoundingBox()).andReturn(envelope).anyTimes();

    expect(catalog.getResource(rId, clazz)).andReturn(r).anyTimes();

    expect(catalog.getResourceByName(ns.getPrefix() + ":" + name, clazz)).andReturn(r).anyTimes();
    expect(catalog.getResourceByName(ns.getPrefix() + ":" + name, ResourceInfo.class))
        .andReturn(r)
        .anyTimes();

    expect(catalog.getResourceByName(name, clazz)).andReturn(r).anyTimes();
    expect(catalog.getResourceByName(name, ResourceInfo.class)).andReturn(r).anyTimes();

    expect(catalog.getResourceByName(new NameImpl(ns.getPrefix(), name), clazz))
        .andReturn(r)
        .anyTimes();
    expect(catalog.getResourceByName(new NameImpl(ns.getPrefix(), name), ResourceInfo.class))
        .andReturn(r)
        .anyTimes();

    expect(catalog.getResourceByName(new NameImpl(ns.getURI(), name), clazz))
        .andReturn(r)
        .anyTimes();
    expect(catalog.getResourceByName(new NameImpl(ns.getURI(), name), ResourceInfo.class))
        .andReturn(r)
        .anyTimes();

    expect(catalog.getResourceByName(ns, name, clazz)).andReturn(r).andReturn(r).anyTimes();
    expect(catalog.getResourceByName(ns, name, ResourceInfo.class))
        .andReturn(r)
        .andReturn(r)
        .anyTimes();

    expect(catalog.getResourceByName(ns.getPrefix(), name, clazz)).andReturn(r).anyTimes();
    expect(catalog.getResourceByName(ns.getPrefix(), name, ResourceInfo.class))
        .andReturn(r)
        .anyTimes();
    // expect(catalog.getResourceByName(or(eq(ns.getPrefix()), eq(ns.getURI())), name,
    //    clazz)).andReturn(r).anyTimes();
    expect(catalog.getResourceByStore(s, name, clazz)).andReturn(r).anyTimes();
    expect(catalog.getResourceByStore(s, name, ResourceInfo.class)).andReturn(r).anyTimes();
  }
  public MockCatalogBuilder coverage(QName qName, String fileName, String srs, Class scope) {
    scope = scope != null ? scope : getClass();

    String cId = newId();
    final CoverageStoreInfo cs = coverageStores.peekLast();
    NamespaceInfo ns = namespaces.peekLast();

    final String name = qName.getLocalPart();
    File dir = new File(dataDirRoot, name);
    dir.mkdir();

    try {
      IOUtils.copy(scope.getResourceAsStream(fileName), new File(dir, fileName));
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

    // initialize the mock by actually building a real one first
    CatalogBuilder cb = new CatalogBuilder(new CatalogImpl());
    cb.setStore(cs);

    GridCoverage2DReader reader = cs.getFormat().getReader(cs.getURL());
    if (reader == null) {
      throw new RuntimeException("No reader for " + cs.getURL());
    }

    CoverageInfo real = null;
    try {
      real = cb.buildCoverage(reader, null);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    final CoverageInfo c = createNiceMock(CoverageInfo.class);
    coverages.add(c);
    final List<CoverageInfo> coverageList = coverages;

    if (srs == null) {
      srs = real.getSRS();
    }
    initResource(
        c,
        CoverageInfo.class,
        cId,
        name,
        cs,
        ns,
        srs,
        real.getProjectionPolicy(),
        real.getNativeBoundingBox(),
        real.getLatLonBoundingBox());

    expect(c.getDefaultInterpolationMethod())
        .andReturn(real.getDefaultInterpolationMethod())
        .anyTimes();
    expect(c.getDimensions()).andReturn(real.getDimensions()).anyTimes();
    expect(c.getGrid()).andReturn(real.getGrid()).anyTimes();

    expect(c.getInterpolationMethods()).andReturn(real.getInterpolationMethods()).anyTimes();
    expect(c.getRequestSRS()).andReturn(real.getRequestSRS()).anyTimes();
    expect(c.getResponseSRS()).andReturn(real.getResponseSRS()).anyTimes();

    try {
      expect(c.getGridCoverageReader(null, null)).andReturn(reader).anyTimes();
    } catch (IOException e) {
    }

    expect(catalog.getCoverageByName(or(eq(name), eq(ns.getPrefix() + ":" + name))))
        .andReturn(c)
        .anyTimes();
    expect(
            catalog.getCoverageByName(
                or(eq(new NameImpl(ns.getPrefix(), name)), eq(new NameImpl(ns.getURI(), name)))))
        .andReturn(c)
        .anyTimes();
    expect(catalog.getCoverageByName(ns, name)).andReturn(c).anyTimes();

    expect(catalog.getCoverageByName(ns.getPrefix(), name)).andReturn(c).anyTimes();
    // expect(catalog.getFeatureTypeByName(or(eq(ns.getPrefix()), eq(ns.getURI())), name))
    //    .andReturn(ft).anyTimes();

    // expect(catalog.getCoverageByStore(cs, name)).andReturn(c).anyTimes();
    expect(catalog.getCoveragesByStore(cs)).andReturn(coverageList).anyTimes();
    expect(catalog.getCoverageByCoverageStore(cs, name)).andReturn(c).anyTimes();

    c.accept((CatalogVisitor) anyObject());
    expectLastCall()
        .andAnswer(
            new VisitAnswer() {
              @Override
              protected void doVisit(CatalogVisitor visitor) {
                visitor.visit(c);
              }
            })
        .anyTimes();

    callback.onResource(name, c, cs, this);
    replay(c, createLayer(c, name, ns));
    return this;
  }
  public MockCatalogBuilder featureType(
      final String name,
      String srs,
      ProjectionPolicy projPolicy,
      ReferencedEnvelope envelope,
      ReferencedEnvelope latLonEnvelope) {

    String ftId = newId();
    final DataStoreInfo ds = dataStores.peekLast();
    NamespaceInfo ns = namespaces.peekLast();

    final FeatureTypeInfo ft = createNiceMock(FeatureTypeInfo.class);
    featureTypes.add(ft);

    initResource(
        ft, FeatureTypeInfo.class, ftId, name, ds, ns, srs, projPolicy, envelope, latLonEnvelope);

    expect(ft.getNumDecimals()).andReturn(8);

    // setup the property file data
    File propDir = new File(dataDirRoot, ds.getName());
    propDir.mkdirs();

    String fileName = name + ".properties";
    try {
      IOUtils.copy(getClass().getResourceAsStream(fileName), new File(propDir, fileName));
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

    try {
      expect(ft.getFeatureType())
          .andAnswer(
              new IAnswer<FeatureType>() {
                @Override
                public FeatureType answer() throws Throwable {
                  return ((DataStore) ds.getDataStore(null)).getSchema(name);
                }
              })
          .anyTimes();
      expect(ft.getFeatureSource(null, null))
          .andAnswer(
              (IAnswer)
                  new IAnswer<FeatureSource>() {
                    @Override
                    public FeatureSource answer() throws Throwable {
                      return ((DataStore) ds.getDataStore(null)).getFeatureSource(name);
                    }
                  })
          .anyTimes();
    } catch (IOException e) {
    }

    expect(catalog.getFeatureTypeByName(or(eq(name), eq(ns.getPrefix() + ":" + name))))
        .andReturn(ft)
        .anyTimes();

    expect(
            catalog.getFeatureTypeByName(
                or(eq(new NameImpl(ns.getPrefix(), name)), eq(new NameImpl(ns.getURI(), name)))))
        .andReturn(ft)
        .anyTimes();
    expect(catalog.getFeatureTypeByName(ns, name)).andReturn(ft).anyTimes();

    expect(catalog.getFeatureTypeByName(ns.getPrefix(), name)).andReturn(ft).anyTimes();
    // expect(catalog.getFeatureTypeByName(or(eq(ns.getPrefix()), eq(ns.getURI())), name))
    //    .andReturn(ft).anyTimes();

    expect(catalog.getFeatureTypeByStore(ds, name)).andReturn(ft).anyTimes();
    expect(catalog.getFeatureTypeByDataStore(ds, name)).andReturn(ft).anyTimes();

    ft.accept((CatalogVisitor) anyObject());
    expectLastCall()
        .andAnswer(
            new VisitAnswer() {
              @Override
              protected void doVisit(CatalogVisitor visitor) {
                visitor.visit(ft);
              }
            })
        .anyTimes();

    callback.onResource(name, ft, ds, this);
    replay(ft, createLayer(ft, name, ns));
    return this;
  }
  /**
   * Process XmlBindings on a per package basis for a given AnnotationsPorcessor instance.
   *
   * @param annotationsProcessor
   */
  public void processXML(
      AnnotationsProcessor annotationsProcessor,
      JavaModelInput jModelInput,
      TypeMappingInfo[] typeMappingInfos,
      JavaClass[] originalJavaClasses) {
    this.jModelInput = jModelInput;
    this.aProcessor = annotationsProcessor;
    Map<String, XmlEnum> xmlEnumMap = new HashMap<String, XmlEnum>();
    annotationsProcessor.init(originalJavaClasses, typeMappingInfos);

    // build a map of packages to JavaClass so we only process the
    // JavaClasses for a given package additional classes - i.e. ones from
    // packages not listed in XML - will be processed later
    Map<String, ArrayList<JavaClass>> pkgToClassMap = buildPackageToJavaClassMap();

    // process each XmlBindings in the map
    XmlBindings xmlBindings;
    for (String packageName : xmlBindingMap.keySet()) {
      ArrayList classesToProcess = pkgToClassMap.get(packageName);
      if (classesToProcess == null) {
        getLogger()
            .logWarning("jaxb_metadata_warning_no_classes_to_process", new Object[] {packageName});
        continue;
      }

      xmlBindings = xmlBindingMap.get(packageName);

      // handle @XmlSchema override
      NamespaceInfo nsInfo = processXmlSchema(xmlBindings, packageName);
      if (nsInfo != null) {
        annotationsProcessor.addPackageToNamespaceMapping(packageName, nsInfo);
      }

      // build an array of JavaModel classes to process
      JavaClass[] javaClasses =
          (JavaClass[]) classesToProcess.toArray(new JavaClass[classesToProcess.size()]);

      // handle xml-enums
      // build a map of enum class names to XmlEnum objects
      XmlEnums xmlEnums = xmlBindings.getXmlEnums();
      if (xmlEnums != null) {
        for (XmlEnum xmlEnum : xmlEnums.getXmlEnum()) {
          xmlEnumMap.put(xmlEnum.getJavaEnum(), xmlEnum);
        }
      }

      // pre-build the TypeInfo objects
      Map<String, TypeInfo> typeInfoMap = annotationsProcessor.preBuildTypeInfo(javaClasses);

      // handle package-level xml-schema-types
      List<XmlSchemaType> xmlSchemaTypes = null;
      XmlSchemaTypes sTypes = xmlBindings.getXmlSchemaTypes();
      if (sTypes != null) {
        xmlSchemaTypes = sTypes.getXmlSchemaType();
      } else {
        xmlSchemaTypes = new ArrayList<XmlSchemaType>();
      }
      // handle package-level xml-schema-type
      if (xmlBindings.getXmlSchemaType() != null) {
        xmlSchemaTypes.add(xmlBindings.getXmlSchemaType());
      }
      // process each xml-schema-type entry
      for (XmlSchemaType sType : xmlSchemaTypes) {
        JavaClass jClass = aProcessor.getHelper().getJavaClass(sType.getType());
        if (jClass != null) {
          aProcessor.processSchemaType(
              sType.getName(), sType.getNamespace(), jClass.getQualifiedName());
        }
      }

      nsInfo = annotationsProcessor.getPackageToNamespaceMappings().get(packageName);

      JavaTypes jTypes = xmlBindings.getJavaTypes();
      if (jTypes != null) {
        for (JavaType javaType : jTypes.getJavaType()) {
          TypeInfo info = typeInfoMap.get(javaType.getName());

          // package/class override order:
          // 1 - xml class-level
          // 2 - java object class-level
          // 3 - xml package-level
          // 4 - package-info.java

          // handle class-level @XmlJavaTypeAdapter override
          if (javaType.getXmlJavaTypeAdapter() != null) {
            info.setXmlJavaTypeAdapter(javaType.getXmlJavaTypeAdapter());
          }

          // handle class-level @XmlAccessorOrder override
          if (javaType.isSetXmlAccessorOrder()) {
            info.setXmlAccessOrder(javaType.getXmlAccessorOrder());
          } else if (!info.isSetXmlAccessOrder()) {
            // handle package-level @XmlAccessorOrder override
            if (xmlBindings.isSetXmlAccessorOrder()) {
              info.setXmlAccessOrder(xmlBindings.getXmlAccessorOrder());
            } else {
              // finally, check the NamespaceInfo
              info.setXmlAccessOrder(nsInfo.getAccessOrder());
            }
          }

          // handle class-level @XmlAccessorType override
          if (javaType.isSetXmlAccessorType()) {
            info.setXmlAccessType(javaType.getXmlAccessorType());
          } else if (!info.isSetXmlAccessType()) {
            if (xmlBindings.isSetXmlAccessorType()) {
              // handle package-level @XmlAccessorType override
              info.setXmlAccessType(xmlBindings.getXmlAccessorType());
            } else {
              // finally, check the NamespaceInfo
              info.setXmlAccessType(nsInfo.getAccessType());
            }
          }

          // handle @XmlInlineBinaryData override
          if (javaType.isSetXmlInlineBinaryData()) {
            info.setInlineBinaryData(javaType.isXmlInlineBinaryData());
          }

          // handle @XmlTransient override
          if (javaType.isSetXmlTransient()) {
            info.setXmlTransient(javaType.isXmlTransient());
          }
          // handle @XmlRootElement
          if (javaType.getXmlRootElement() != null) {
            info.setXmlRootElement(javaType.getXmlRootElement());
          }
          // handle @XmlSeeAlso override
          if (javaType.getXmlSeeAlso() != null && javaType.getXmlSeeAlso().size() > 0) {
            info.setXmlSeeAlso(javaType.getXmlSeeAlso());
          }
          // handle @XmlType override
          if (javaType.getXmlType() != null) {
            info.setXmlType(javaType.getXmlType());
          }
          // handle @XmlCustomizer override
          if (javaType.getXmlCustomizer() != null) {
            info.setXmlCustomizer(javaType.getXmlCustomizer());
          }
        }
      }

      // apply package-level @XmlJavaTypeAdapters
      if (xmlBindings.getXmlJavaTypeAdapters() != null) {
        Map<String, TypeInfo> typeInfos = aProcessor.getTypeInfosForPackage(packageName);
        for (TypeInfo tInfo : typeInfos.values()) {
          List<XmlJavaTypeAdapter> adapters =
              xmlBindings.getXmlJavaTypeAdapters().getXmlJavaTypeAdapter();
          for (XmlJavaTypeAdapter xja : adapters) {
            JavaClass adapterClass = jModelInput.getJavaModel().getClass(xja.getValue());
            JavaClass boundType = jModelInput.getJavaModel().getClass(xja.getType());
            if (boundType != null) {
              tInfo.addPackageLevelAdapterClass(adapterClass, boundType);
            }
          }
        }
      }

      // post-build the TypeInfo objects
      javaClasses = annotationsProcessor.postBuildTypeInfo(javaClasses);

      // now trigger the annotations processor to process the classes
      annotationsProcessor.processJavaClasses(javaClasses);

      // get the generated TypeInfo
      Map<String, TypeInfo> typeInfosForPackage =
          annotationsProcessor.getTypeInfosForPackage(packageName);

      // update xml-enum info if necessary
      for (String key : typeInfosForPackage.keySet()) {
        TypeInfo tInfo = typeInfosForPackage.get(key);
        if (tInfo.isEnumerationType()) {
          EnumTypeInfo etInfo = (EnumTypeInfo) tInfo;
          XmlEnum xmlEnum = xmlEnumMap.get(etInfo.getClassName());
          if (xmlEnum != null) {
            JavaClass restrictionClass = aProcessor.getHelper().getJavaClass(xmlEnum.getValue());
            // default to String if necessary
            if (restrictionClass == null) {
              restrictionClass = jModelInput.getJavaModel().getClass(String.class);
            }
            etInfo.setRestrictionBase(aProcessor.getSchemaTypeFor(restrictionClass));
            for (XmlEnumValue xmlEnumValue : xmlEnum.getXmlEnumValue()) {
              // overwrite any existing entries (from annotations)
              etInfo.addJavaFieldToXmlEnumValuePair(
                  true, xmlEnumValue.getJavaEnumValue(), xmlEnumValue.getValue());
            }
          }
        }
      }

      // update TypeInfo objects based on the JavaTypes
      jTypes = xmlBindings.getJavaTypes();
      if (jTypes != null) {
        for (JavaType javaType : jTypes.getJavaType()) {
          processJavaType(javaType, typeInfosForPackage.get(javaType.getName()), nsInfo);
        }
      }
      // remove the entry for this package from the map
      pkgToClassMap.remove(packageName);
    }

    // now process remaining classes
    Iterator<ArrayList<JavaClass>> classIt = pkgToClassMap.values().iterator();
    while (classIt.hasNext()) {
      ArrayList<JavaClass> jClassList = classIt.next();
      JavaClass[] jClassArray = (JavaClass[]) jClassList.toArray(new JavaClass[jClassList.size()]);
      annotationsProcessor.buildNewTypeInfo(jClassArray);
      annotationsProcessor.processJavaClasses(jClassArray);
    }

    // need to ensure that any bound types (from XmlJavaTypeAdapter) have
    // TypeInfo objects built for them - SchemaGenerator will require a
    // descriptor for each
    Map<String, TypeInfo> typeInfos = (Map<String, TypeInfo>) aProcessor.getTypeInfo().clone();
    for (String key : typeInfos.keySet()) {
      JavaClass[] jClassArray;
      TypeInfo tInfo = typeInfos.get(key);
      for (Property prop : tInfo.getPropertyList()) {
        if (prop.isSetXmlJavaTypeAdapter()) {
          jClassArray = new JavaClass[] {prop.getActualType()};
          aProcessor.buildNewTypeInfo(jClassArray);
        }
      }
    }
    aProcessor.finalizeProperties();
    aProcessor.createElementsForTypeMappingInfo();
  }
  /**
   * XmlElement override will completely replace the existing values.
   *
   * @param xmlElement
   * @param oldProperty
   * @param typeInfo
   * @param nsInfo
   * @return
   */
  private Property processXmlElement(
      XmlElement xmlElement, Property oldProperty, TypeInfo typeInfo, NamespaceInfo nsInfo) {
    // reset any existing values
    resetProperty(oldProperty, typeInfo);

    if (xmlElement.getXmlMap() != null) {
      processXmlMap(xmlElement.getXmlMap(), oldProperty);
    }

    // handle xml-id
    if (xmlElement.isXmlId()) {
      typeInfo.setIDProperty(oldProperty);
    } else if (oldProperty.isXmlId()) {
      // account for XmlID un-set via XML
      if (typeInfo.getIDProperty() != null
          && typeInfo.getIDProperty().getPropertyName().equals(oldProperty.getPropertyName())) {
        typeInfo.setIDProperty(null);
      }
    }
    oldProperty.setIsXmlId(xmlElement.isXmlId());

    // handle xml-idref
    oldProperty.setIsXmlIdRef(xmlElement.isXmlIdref());

    // set required
    oldProperty.setIsRequired(xmlElement.isRequired());

    // set xml-inline-binary-data
    oldProperty.setisInlineBinaryData(xmlElement.isXmlInlineBinaryData());

    // set nillable
    oldProperty.setNillable(xmlElement.isNillable());

    // set defaultValue
    if (xmlElement.getDefaultValue().equals("\u0000")) {
      oldProperty.setDefaultValue(null);
    } else {
      oldProperty.setDefaultValue(xmlElement.getDefaultValue());
    }

    // set schema name
    QName qName;
    String name = xmlElement.getName();
    if (name.equals("##default")) {
      name = oldProperty.getPropertyName();
    }
    if (xmlElement.getNamespace().equals("##default")) {
      if (nsInfo.isElementFormQualified()) {
        qName = new QName(nsInfo.getNamespace(), name);
      } else {
        qName = new QName(name);
      }
    } else {
      qName = new QName(xmlElement.getNamespace(), name);
    }
    oldProperty.setSchemaName(qName);

    // set type
    if (xmlElement.getType().equals("javax.xml.bind.annotation.XmlElement.DEFAULT")) {
      // if xmlElement has no type, and the property type was set via
      // @XmlElement, reset it to the original value
      if (oldProperty.isXmlElementType()) {
        oldProperty.setType(oldProperty.getOriginalType());
      }
    } else {
      if (xmlElement.getXmlMap() != null) {
        getLogger()
            .logWarning(
                JAXBMetadataLogger.INVALID_TYPE_ON_MAP, new Object[] {xmlElement.getName()});
      } else {
        oldProperty.setType(jModelInput.getJavaModel().getClass(xmlElement.getType()));
      }
    }

    // handle XmlJavaTypeAdapter
    if (xmlElement.getXmlJavaTypeAdapter() != null) {
      oldProperty.setXmlJavaTypeAdapter(xmlElement.getXmlJavaTypeAdapter());
    }

    // handle XmlElementWrapper
    if (xmlElement.getXmlElementWrapper() != null) {
      oldProperty.setXmlElementWrapper(xmlElement.getXmlElementWrapper());
    }

    // for primitives we always set required, a.k.a. minOccurs="1"
    if (!oldProperty.isRequired()) {
      JavaClass ptype = oldProperty.getActualType();
      oldProperty.setIsRequired(
          ptype.isPrimitive() || ptype.isArray() && ptype.getComponentType().isPrimitive());
    }

    // handle xml-list
    if (xmlElement.isSetXmlList()) {
      // Make sure XmlList annotation is on a collection or array
      if (!aProcessor.isCollectionType(oldProperty) && !oldProperty.getType().isArray()) {
        throw JAXBException.invalidList(oldProperty.getPropertyName());
      }
      oldProperty.setIsXmlList(xmlElement.isXmlList());
    }

    // handle xml-mime-type
    if (xmlElement.getXmlMimeType() != null) {
      oldProperty.setMimeType(xmlElement.getXmlMimeType());
    }

    // handle xml-attachment-ref
    if (xmlElement.isXmlAttachmentRef()) {
      oldProperty.setIsSwaAttachmentRef(true);
      oldProperty.setSchemaType(XMLConstants.SWA_REF_QNAME);
    }

    // handle xml-schema-type
    if (xmlElement.getXmlSchemaType() != null) {
      oldProperty.setSchemaType(
          new QName(
              xmlElement.getXmlSchemaType().getNamespace(),
              xmlElement.getXmlSchemaType().getName()));
    }

    return oldProperty;
  }
  /**
   * XmlAttribute override will completely replace the existing values.
   *
   * @param xmlAttribute
   * @param oldProperty
   * @param nsInfo
   * @return
   */
  private Property processXmlAttribute(
      XmlAttribute xmlAttribute, Property oldProperty, TypeInfo typeInfo, NamespaceInfo nsInfo) {
    // reset any existing values
    resetProperty(oldProperty, typeInfo);

    // handle xml-id
    if (xmlAttribute.isXmlId()) {
      typeInfo.setIDProperty(oldProperty);
    } else if (oldProperty.isXmlId()) {
      // account for XmlID un-set via XML
      if (typeInfo.getIDProperty() != null
          && typeInfo.getIDProperty().getPropertyName().equals(oldProperty.getPropertyName())) {
        typeInfo.setIDProperty(null);
      }
    }
    oldProperty.setIsXmlId(xmlAttribute.isXmlId());

    // handle xml-idref
    oldProperty.setIsXmlIdRef(xmlAttribute.isXmlIdref());

    // set isAttribute
    oldProperty.setIsAttribute(true);

    // set required
    oldProperty.setIsRequired(xmlAttribute.isRequired());

    // set xml-inline-binary-data
    oldProperty.setisInlineBinaryData(xmlAttribute.isXmlInlineBinaryData());

    // set schema name
    QName qName;
    String name = xmlAttribute.getName();
    if (name.equals("##default")) {
      name = oldProperty.getPropertyName();
    }
    if (xmlAttribute.getNamespace().equals("##default")) {
      if (nsInfo.isElementFormQualified()) {
        qName = new QName(nsInfo.getNamespace(), name);
      } else {
        qName = new QName(name);
      }
    } else {
      qName = new QName(xmlAttribute.getNamespace(), name);
    }
    oldProperty.setSchemaName(qName);

    // handle XmlJavaTypeAdapter
    if (xmlAttribute.getXmlJavaTypeAdapter() != null) {
      oldProperty.setXmlJavaTypeAdapter(xmlAttribute.getXmlJavaTypeAdapter());
    }

    // handle xml-mime-type
    if (xmlAttribute.getXmlMimeType() != null) {
      oldProperty.setMimeType(xmlAttribute.getXmlMimeType());
    }

    // handle xml-attachment-ref
    if (xmlAttribute.isXmlAttachmentRef()) {
      oldProperty.setIsSwaAttachmentRef(true);
      oldProperty.setSchemaType(XMLConstants.SWA_REF_QNAME);
    }

    // handle xml-schema-type
    if (xmlAttribute.getXmlSchemaType() != null) {
      oldProperty.setSchemaType(
          new QName(
              xmlAttribute.getXmlSchemaType().getNamespace(),
              xmlAttribute.getXmlSchemaType().getName()));
    }

    return oldProperty;
  }