com.android.repository.api.SchemaModule Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of repository Show documentation
Show all versions of repository Show documentation
A library for downloading and managing package repositories
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.repository.api;
import com.android.annotations.NonNull;
import com.google.common.collect.Maps;
import java.io.File;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlTransient;
/**
* Represents a versioned set of generated classes corresponding to a versioned XML schema.
*
* This can be a single stand-alone schema, or an extension to an existing schema. For example,
* {@code repo-common-N.xsd} defines a schema for a repository with packages, and the collection of
* the schemas for all N would be represented by a single {@code SchemaModule} instance.
* They can then be used for marshalling or unmarshalling XML documents by the repository framework.
*/
@XmlTransient
public class SchemaModule {
/**
* Map of XML namespaces to the SchemaModuleVersions making up this module.
*/
private final Map mVersions = Maps.newHashMap();
/**
* Reference to the highest version found. Used by default when creating new objects.
*/
private final SchemaModuleVersion mLatestVersion;
/**
* Class used with {@link Class#getResourceAsStream(String)} to look up xsd resources.
*/
private final Class mResourceRoot;
/**
* @param ofPattern Fully-qualified class name of the JAXB {@code ObjectFactory} classes
* making up this module. Should have a single %d parameter, corresponding to
* the 1-indexed version of the schema.
* @param xsdPattern Filename pattern of the XSDs making up this module. Should have a single
* %d parameter, corresponding to the 1-indexed version of the schema.
* @param resourceRoot A class instance used via {@link Class#getResource(String)} to read
* the XSD file.
*/
public SchemaModule(@NonNull String ofPattern, @NonNull String xsdPattern,
@NonNull Class resourceRoot) {
if (!ofPattern.matches(".*%[0-9.$]*d.*") || !xsdPattern.matches(".*%[0-9.$]*d.*")) {
assert false : "ofPattern and xsdPattern must contain a single %d parameter";
}
SchemaModuleVersion version = null;
for (int i = 1; ; i++) {
Class objectFactory;
try {
objectFactory = Class.forName(String.format(ofPattern, i));
} catch (ClassNotFoundException e) {
break;
}
String xsdLocation = String.format(xsdPattern, i);
version = new SchemaModuleVersion(objectFactory, xsdLocation);
mVersions.put(version.getNamespace(), version);
}
mLatestVersion = version;
assert !mVersions.isEmpty() : "No versions found";
mResourceRoot = resourceRoot;
}
/**
* Creates an {@code ObjectFactory} for the latest known version of this module.
*/
@NonNull
public Object createLatestFactory() {
Class of = mLatestVersion.getObjectFactory();
try {
return of.newInstance();
} catch (IllegalAccessException e) {
assert false : e;
} catch (InstantiationException e) {
assert false : e;
}
return null;
}
/**
* Gets the map of namespaces to {@link SchemaModuleVersion}s. Should only be needed by
* the repository framework.
*/
@NonNull
public Map getNamespaceVersionMap() {
return mVersions;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SchemaModule)) {
return false;
}
return mVersions.equals(((SchemaModule)obj).getNamespaceVersionMap());
}
@Override
public int hashCode() {
return mVersions.hashCode();
}
/**
* Gets the namespace prefix (the namespace with the final number (if any) removed) for our
* latest schema version.
*/
@NonNull
public String getNamespacePrefix() {
return mLatestVersion.getNamespacePrefix();
}
/**
* Gets the namespace of the our latest schema version.
*/
public String getLatestNamespace() {
return mLatestVersion.getNamespace();
}
/**
* Represents a single version of a schema, including a single XSD and a single
* {@code ObjectFactory}.
*/
public class SchemaModuleVersion {
private final Class mObjectFactory;
private final String mXsdLocation;
private final String mNamespace;
/**
* @param objectFactory The xjc-generated {@code ObjectFactory} instance for this schema
* version. Notably, the package containing this class must contain
* a {@code package-info.java} with a {@link XmlSchema} annotation
* giving the XML namespace of this schema.
* @param xsd The XSD file for this schema.
*/
public SchemaModuleVersion(@NonNull Class objectFactory, @NonNull String xsdLocation) {
mObjectFactory = objectFactory;
mXsdLocation = xsdLocation;
String namespace = objectFactory.getPackage().getAnnotation(XmlSchema.class)
.namespace();
assert namespace != null : "Can't create schema module version with no namespace";
mNamespace = namespace;
}
/**
* Gets the {@code ObjectFactory} for this schema version.
*/
@NonNull
public Class getObjectFactory() {
return mObjectFactory;
}
/**
* Gets the XSD file for this schema version.
*/
@NonNull
public InputStream getXsd() {
return mResourceRoot.getResourceAsStream(mXsdLocation);
}
/**
* Gets the target namespace of this schema version.
*/
@NonNull
public String getNamespace() {
return mNamespace;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SchemaModuleVersion)) {
return false;
}
return mXsdLocation.equals(((SchemaModuleVersion)obj).mXsdLocation) &&
mNamespace.equals(((SchemaModuleVersion)obj).mNamespace);
}
@Override
public int hashCode() {
return mXsdLocation.hashCode() * 37 + mNamespace.hashCode();
}
/**
* Gets our namespace prefix (the namespace with the final number (if any) removed).
*/
@NonNull
public String getNamespacePrefix() {
return mNamespace.replaceAll("/[0-9]*$", "/");
}
}
}