/** * Copyright (C) 2012 the original author or authors. * * 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 co.jirm.mapper.definition; import static com.google.common.collect.Maps.newLinkedHashMap; import static java.util.Collections.emptyList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import javax.persistence.Table; import static co.jirm.core.util.JirmPrecondition.check; import co.jirm.mapper.SqlObjectConfig; import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.base.Splitter; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.util.concurrent.UncheckedExecutionException; public class SqlObjectDefinition<T> { private final Class<T> objectType; private final Map<String, SqlParameterDefinition> parameters; private final Map<String, SqlParameterDefinition> sqlNameToParameter; private final Map<String, SqlParameterDefinition> idParameters; private final Map<String, SqlParameterDefinition> manyToOneParameters; private final Map<String, SqlParameterDefinition> simpleParameters; private final String sqlName; private SqlObjectDefinition(SqlObjectConfig config, Class<T> objectType, Map<String, SqlParameterDefinition> parameters) { super(); this.objectType = objectType; this.parameters = parameters; LinkedHashMap<String, SqlParameterDefinition> n = newLinkedHashMap(); LinkedHashMap<String, SqlParameterDefinition> id = newLinkedHashMap(); LinkedHashMap<String, SqlParameterDefinition> m = newLinkedHashMap(); LinkedHashMap<String, SqlParameterDefinition> s = newLinkedHashMap(); for(Entry<String, SqlParameterDefinition> e : parameters.entrySet()) { n.put(e.getValue().sqlName(), e.getValue()); if (e.getValue().isId()) { id.put(e.getKey(), e.getValue()); } if (e.getValue().getObjectDefinition().isPresent()) { m.put(e.getKey(), e.getValue()); } else { s.put(e.getKey(), e.getValue()); } } sqlNameToParameter = ImmutableMap.copyOf(n); idParameters = ImmutableMap.copyOf(id); manyToOneParameters = ImmutableMap.copyOf(m); simpleParameters = ImmutableMap.copyOf(s); Table t = objectType.getAnnotation(Table.class); if (t != null && t.name() != null) { sqlName = t.name(); } else { sqlName = config.getNamingStrategy().classToTableName(objectType.getSimpleName()); } } @SuppressWarnings({ "rawtypes", "unchecked" }) private static <T> SqlObjectDefinition<T> _fromClass(Class<T> c, SqlObjectConfig config) { return new SqlObjectDefinition(config, c, ImmutableMap.copyOf(SqlParameterDefinition.getSqlBeanParameters(c, config))); } // public static <T> SqlObjectDefinition<T> fromClass(Class<T> c) { // return fromClass(c, SqlObjectConfig.DEFAULT); // } @SuppressWarnings("unchecked") public static <T> SqlObjectDefinition<T> fromClass(final Class<T> objectType, final SqlObjectConfig config) { try { return (SqlObjectDefinition<T>) config.getCache().get(objectType, new Callable<SqlObjectDefinition<?>>() { @Override public SqlObjectDefinition<?> call() throws Exception { return SqlObjectDefinition._fromClass(objectType, config); } }); } catch (ExecutionException e) { throw Throwables.propagate(e); } catch (UncheckedExecutionException e) { throw Throwables.propagate(Objects.firstNonNull(e.getCause(), e)); } } public Class<T> getObjectType() { return objectType; } public Map<String,SqlParameterDefinition> getParameters() { return parameters; } public Map<String, SqlParameterDefinition> getManyToOneParameters() { return manyToOneParameters; } public Map<String, SqlParameterDefinition> getSqlNameToParameter() { return sqlNameToParameter; } public Optional<SqlParameterDefinition> resolveParameter(String parameter) { if (getSqlNameToParameter().containsKey(parameter)) return Optional.of(getSqlNameToParameter().get(parameter)); if (getParameters().containsKey(parameter)) return Optional.of(getParameters().get(parameter)); return Optional.absent(); } public Optional<String> parameterNameToSql(String parameter) { SqlParameterDefinition d = getParameters().get(parameter); if (d == null) return Optional.absent(); return Optional.of(d.sqlName()); } private final static Splitter dotSplitter = Splitter.on("."); public List<SqlParameterDefinition> resolveParameterPath(String parameterDotPath) { Iterator<String> it = dotSplitter.split(parameterDotPath).iterator(); List<SqlParameterDefinition> r = Lists.newArrayList(); SqlObjectDefinition<?> currentObject = this; while(it.hasNext()) { String pathPart = it.next(); Optional<SqlParameterDefinition> p = currentObject.resolveParameter(pathPart); if ( ! p.isPresent() ) return emptyList(); check.state( ! ( it.hasNext() && ! p.get().isComplex()), "Bad path parts references a simple parameter: {}", parameterDotPath); r.add(p.get()); if (it.hasNext()) currentObject = p.get().getObjectDefinition().get().getObjectDefintion(); } return r; } public Map<String, SqlParameterDefinition> getIdParameters() { return idParameters; } public Map<String, SqlParameterDefinition> getSimpleParameters() { return simpleParameters; } public Optional<SqlParameterDefinition> idParameter() { return Optional.fromNullable(Iterators.get(this.getIdParameters().values().iterator(), 0, null)); } public String getSqlName() { return sqlName; } }