mirror of
https://github.com/google/nomulus
synced 2026-01-03 19:54:18 +00:00
A tool to visualize the layout of our schema in datastore.
The output on the current schema is:
CommitLogBucket (not backed up)
↳ CommitLogManifest (not backed up)
↳ CommitLogMutation (not backed up)
CommitLogCheckpointRoot (not backed up)
↳ CommitLogCheckpoint (not backed up)
DomainApplicationIndex (bgr)
EntityGroupRoot (bgr)
↳ ClaimsListShard.ClaimsListSingleton (not backed up)
↳ ClaimsListShard.ClaimsListRevision (virtual)
↳ ClaimsListShard (not backed up)
↳ LogsExportCursor
↳ PremiumList
↳ PremiumList.PremiumListRevision (virtual)
↳ PremiumList.PremiumListEntry
↳ Registrar
↳ RegistrarBillingEntry
↳ RegistrarContact
↳ RegistrarCredit
↳ RegistrarCreditBalance
↳ Registry (bgr)
↳ RegistryCursor
↳ ReservedList
↳ ServerSecret (not backed up)
↳ SignedMarkRevocationList (not backed up)
↳ TmchCrl (not backed up)
EppResource (abstract) (bgr)
- ContactResource
- DomainBase
- DomainApplication (subclass)
- DomainResource (subclass)
- HostResource
↳ HistoryEntry
↳ BillingEvent.Cancellation
↳ BillingEvent.Modification
↳ BillingEvent.OneTime
↳ BillingEvent.Recurring
↳ PollMessage (abstract)
- PollMessage.Autorenew (subclass)
- PollMessage.OneTime (subclass)
EppResourceIndexBucket (virtual)
↳ EppResourceIndex (bgr)
ForeignKeyIndex.ForeignKeyContactIndex (bgr)
ForeignKeyIndex.ForeignKeyDomainIndex (bgr)
ForeignKeyIndex.ForeignKeyHostIndex (bgr)
GaeUserIdConverter (not backed up)
Lock (not backed up)
RdeRevision
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=120251537
This commit is contained in:
committed by
Justine Tunney
parent
4ba8c0e552
commit
6f72af2ba6
167
java/com/google/domain/registry/tools/GetSchemaTreeCommand.java
Normal file
167
java/com/google/domain/registry/tools/GetSchemaTreeCommand.java
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.google.domain.registry.tools;
|
||||
|
||||
import static com.google.common.collect.Ordering.arbitrary;
|
||||
import static com.google.domain.registry.model.EntityClasses.ALL_CLASSES;
|
||||
import static java.lang.ClassLoader.getSystemClassLoader;
|
||||
import static java.lang.reflect.Modifier.isAbstract;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.collect.TreeMultimap;
|
||||
import com.google.domain.registry.model.BackupGroupRoot;
|
||||
import com.google.domain.registry.model.annotations.NotBackedUp;
|
||||
import com.google.domain.registry.model.annotations.VirtualEntity;
|
||||
import com.google.domain.registry.tools.Command.GtechCommand;
|
||||
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.EntitySubclass;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** Visualizes the schema parentage tree. */
|
||||
@Parameters(commandDescription = "Generate a model schema file")
|
||||
final class GetSchemaTreeCommand implements GtechCommand {
|
||||
|
||||
/** Mapping from parent classes in the Datastore sense to child classes. */
|
||||
private final Multimap<Class<?>, Class<?>> hierarchy =
|
||||
TreeMultimap.create(arbitrary(), new PrintableNameOrdering());
|
||||
|
||||
/** Mapping from superclasses used in parentage to concrete subclasses. */
|
||||
private Multimap<Class<?>, Class<?>> superclassToSubclasses;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
// Get the @Parent type for each class.
|
||||
Map<Class<?>, Class<?>> entityToParentType = new HashMap<>();
|
||||
for (Class<?> clazz : ALL_CLASSES) {
|
||||
entityToParentType.put(clazz, getParentType(clazz));
|
||||
}
|
||||
// Find super types like EppResource that are used as parents in place of actual entity types.
|
||||
Set<Class<?>> superclasses = new HashSet<>();
|
||||
for (Class<?> clazz : ALL_CLASSES) {
|
||||
Class<?> parentType = entityToParentType.get(clazz);
|
||||
if (!ALL_CLASSES.contains(parentType) && !Object.class.equals(parentType)) {
|
||||
superclasses.add(parentType);
|
||||
}
|
||||
}
|
||||
// Find the subclasses for each superclass we just found, and map them to their superclasses.
|
||||
Map<Class<?>, Class<?>> subclassToSuperclass = new HashMap<>();
|
||||
for (Class<?> clazz : ALL_CLASSES) {
|
||||
for (Class<?> superclass : superclasses) {
|
||||
if (superclass.isAssignableFrom(clazz)) {
|
||||
subclassToSuperclass.put(clazz, superclass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Map @EntitySubclass classes to their superclasses.
|
||||
for (Class<?> clazz : ALL_CLASSES) {
|
||||
if (clazz.isAnnotationPresent(EntitySubclass.class)) {
|
||||
Class<?> entityClass = clazz;
|
||||
while (!entityClass.isAnnotationPresent(Entity.class)) {
|
||||
entityClass = entityClass.getSuperclass();
|
||||
}
|
||||
if (subclassToSuperclass.containsKey(clazz)) {
|
||||
subclassToSuperclass.put(entityClass, subclassToSuperclass.get(clazz));
|
||||
}
|
||||
subclassToSuperclass.put(clazz, entityClass);
|
||||
}
|
||||
}
|
||||
// Build the parentage hierarchy, replacing subclasses with superclasses wherever possible.
|
||||
for (Class<?> clazz : ALL_CLASSES) {
|
||||
Class<?> superclass = clazz;
|
||||
while (subclassToSuperclass.containsKey(superclass)) {
|
||||
superclass = subclassToSuperclass.get(superclass);
|
||||
}
|
||||
hierarchy.put(entityToParentType.get(clazz), superclass == null ? clazz : superclass);
|
||||
}
|
||||
// Build up the superclass to subclass mapping.
|
||||
superclassToSubclasses = Multimaps.invertFrom(
|
||||
Multimaps.forMap(subclassToSuperclass),
|
||||
TreeMultimap.<Class<?>, Class<?>>create(arbitrary(), new PrintableNameOrdering()));
|
||||
printTree(Object.class, 0);
|
||||
}
|
||||
|
||||
private Class<?> getParentType(Class<?> clazz) {
|
||||
for (; clazz != null; clazz = clazz.getSuperclass()) {
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.isAnnotationPresent(Parent.class)) {
|
||||
try {
|
||||
return getSystemClassLoader().loadClass(
|
||||
((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]
|
||||
.toString()
|
||||
.replace("? extends ", "")
|
||||
.replace("class ", ""));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
private void printTree(Class<?> parent, int indent) {
|
||||
for (Class<?> clazz : hierarchy.get(parent)) {
|
||||
System.out.println(new StringBuilder(Strings.repeat(" ", indent))
|
||||
.append(indent == 0 ? "" : "↳ ")
|
||||
.append(getPrintableName(clazz))
|
||||
.append(isAbstract(clazz.getModifiers()) ? " (abstract)" : "")
|
||||
.append(clazz.isAnnotationPresent(VirtualEntity.class) ? " (virtual)" : "")
|
||||
.append(clazz.isAnnotationPresent(NotBackedUp.class) ? " (not backed up)" : "")
|
||||
.append(BackupGroupRoot.class.isAssignableFrom(clazz) ? " (bgr)" : ""));
|
||||
printSubclasses(clazz, indent + 2);
|
||||
printTree(clazz, indent + 2);
|
||||
if (indent == 0) {
|
||||
System.out.println(); // Separate the entity groups with a line.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void printSubclasses(Class<?> parent, int indent) {
|
||||
for (Class<?> clazz : superclassToSubclasses.get(parent)) {
|
||||
System.out.println(new StringBuilder(Strings.repeat(" ", indent))
|
||||
.append("- ")
|
||||
.append(getPrintableName(clazz))
|
||||
.append(clazz.isAnnotationPresent(EntitySubclass.class) ? " (subclass)" : ""));
|
||||
printSubclasses(clazz, indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
static String getPrintableName(Class<?> clazz) {
|
||||
return clazz.isMemberClass()
|
||||
? getPrintableName(clazz.getDeclaringClass()) + "." + clazz.getSimpleName()
|
||||
: clazz.getSimpleName();
|
||||
}
|
||||
|
||||
static class PrintableNameOrdering extends Ordering<Class<?>> implements Serializable {
|
||||
@Override
|
||||
public int compare(Class<?> left, Class<?> right) {
|
||||
return getPrintableName(left).compareTo(getPrintableName(right));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ public final class GtechTool {
|
||||
.put("get_host", GetHostCommand.class)
|
||||
.put("get_registrar", GetRegistrarCommand.class)
|
||||
.put("get_schema", GetSchemaCommand.class)
|
||||
.put("get_schema_tree", GetSchemaTreeCommand.class)
|
||||
.put("get_tld", GetTldCommand.class)
|
||||
.put("hash_certificate", HashCertificateCommand.class)
|
||||
.put("list_credits", ListCreditsCommand.class)
|
||||
|
||||
Reference in New Issue
Block a user