1 package com.atlassian.activeobjects;
2
3 import com.atlassian.activeobjects.external.IgnoreReservedKeyword;
4 import com.atlassian.plugin.PluginException;
5 import com.google.common.base.Predicate;
6 import com.google.common.collect.ImmutableSet;
7 import net.java.ao.ActiveObjectsException;
8 import net.java.ao.Common;
9 import net.java.ao.Polymorphic;
10 import net.java.ao.RawEntity;
11 import net.java.ao.schema.FieldNameConverter;
12 import net.java.ao.schema.Ignore;
13 import net.java.ao.schema.NameConverters;
14 import net.java.ao.schema.TableNameConverter;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 import java.lang.reflect.Method;
19 import java.util.Set;
20
21 import static com.google.common.collect.Iterables.any;
22
23 public final class NamesLengthAndOracleReservedWordsEntitiesValidator implements EntitiesValidator {
24 static final Set<String> RESERVED_WORDS = ImmutableSet.of("BLOB", "CLOB", "NUMBER", "ROWID", "TIMESTAMP", "VARCHAR2");
25 static final int MAX_NUMBER_OF_ENTITIES = 200;
26
27 private final Logger logger = LoggerFactory.getLogger(this.getClass());
28
29 @Override
30 public Set<Class<? extends RawEntity<?>>> check(Set<Class<? extends RawEntity<?>>> entityClasses, NameConverters nameConverters) {
31 if (entityClasses.size() > MAX_NUMBER_OF_ENTITIES) {
32 throw new PluginException("Plugins are allowed no more than " + MAX_NUMBER_OF_ENTITIES + " entities!");
33 }
34 for (Class<? extends RawEntity<?>> entityClass : entityClasses) {
35 check(entityClass, nameConverters);
36 }
37 return entityClasses;
38 }
39
40 void check(Class<? extends RawEntity<?>> entityClass, NameConverters nameConverters) {
41 checkTableName(entityClass, nameConverters.getTableNameConverter());
42
43 final FieldNameConverter fieldNameConverter = nameConverters.getFieldNameConverter();
44 for (Method method : entityClass.getMethods()) {
45 checkColumnName(method, fieldNameConverter);
46 checkPolymorphicColumnName(method, fieldNameConverter);
47 }
48 }
49
50 void checkTableName(Class<? extends RawEntity<?>> entityClass, TableNameConverter tableNameConverter) {
51 final String tableName = tableNameConverter.getName(entityClass);
52 if (isReservedWord(tableName)) {
53 throw new ActiveObjectsException("Entity class' '" + entityClass.getName() + "' table name is " + tableName + " which is a reserved word!");
54 }
55 }
56
57 void checkColumnName(Method method, FieldNameConverter fieldNameConverter) {
58 if ((Common.isAccessor(method) || Common.isMutator(method)) && !method.isAnnotationPresent(Ignore.class)) {
59 final String columnName = fieldNameConverter.getName(method);
60 if (isReservedWord(columnName)) {
61 if (method.isAnnotationPresent(IgnoreReservedKeyword.class)) {
62 logger.warn("Method " + method + " is annotated with " + IgnoreReservedKeyword.class.getName() + ", it may cause issue on Oracle. " +
63 "You should change this column name to a non-reserved keyword! "
64 + "The list of reserved keywords is the following: " + RESERVED_WORDS);
65 } else {
66 throw new ActiveObjectsException("Method '" + method + "' column name is " + columnName + " which is a reserved word!");
67 }
68 }
69 }
70 }
71
72 private boolean isReservedWord(final String name) {
73 return any(RESERVED_WORDS, new Predicate<String>() {
74 @Override
75 public boolean apply(String reservedWord) {
76 return reservedWord.equalsIgnoreCase(name);
77 }
78 });
79 }
80
81 void checkPolymorphicColumnName(Method method, FieldNameConverter fieldNameConverter) {
82 final Class<?> attributeTypeFromMethod = Common.getAttributeTypeFromMethod(method);
83 if (attributeTypeFromMethod != null && attributeTypeFromMethod.isAnnotationPresent(Polymorphic.class)) {
84 final String polyTypeName = fieldNameConverter.getPolyTypeName(method);
85 if (isReservedWord(polyTypeName)) {
86 throw new ActiveObjectsException("Method '" + method + "' polymorphic column name is " + polyTypeName + " which is a reserved word!");
87 }
88 }
89 }
90 }