/* * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * 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 org.jboss.errai.jpa.sync.client.shared; import java.util.Collections; import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import javax.persistence.metamodel.EntityType; import org.jboss.errai.common.client.api.Assert; import org.jboss.errai.common.client.api.annotations.MapsTo; import org.jboss.errai.common.client.api.annotations.Portable; @Portable public class SyncableDataSet<E> { private final String queryName; private final Map<String, Object> params; /** Stored as a string so to keep SyncableDataSet marshallable. */ private final String resultTypeFqcn; // FIXME need to allow app to specify TemporalType for date params public static <E> SyncableDataSet<E> from(String queryName, Class<E> resultType, Map<String, Object> params) { return new SyncableDataSet<E>(queryName, resultType, params); } private SyncableDataSet(String queryName, Class<E> resultType, Map<String, Object> params) { this(queryName, resultType.getName(), params); } // Errai Marshalling constructor private SyncableDataSet( @MapsTo("queryName") String queryName, @MapsTo("resultTypeFqcn") String resultTypeFqcn, @MapsTo("params") Map<String, Object> params) { this.queryName = Assert.notNull(queryName); this.resultTypeFqcn = resultTypeFqcn; this.params = Collections.unmodifiableMap(params); } public TypedQuery<E> createQuery(EntityManager em) { TypedQuery<E> query = em.createNamedQuery(queryName, getResultType(em)); for (Map.Entry<String, Object> param : params.entrySet()) { // FIXME should use TemporalType arg here when necessary query.setParameter(param.getKey(), param.getValue()); } return query; } @SuppressWarnings("unchecked") private Class<E> getResultType(EntityManager em) { // We support this so users don't have to specify the query return type when using @Sync. if (resultTypeFqcn.equals("java.lang.Object")) { return (Class<E>) Object.class; } for (EntityType<?> et : em.getMetamodel().getEntities()) { if (et.getJavaType().getName().equals(resultTypeFqcn)) { return ((EntityType<E>) et).getJavaType(); } } throw new IllegalStateException("Result type " + resultTypeFqcn + " is not known to the EntityManager."); } /** * Returns the name of the JPA named query this syncable data set is tied to. * * @return the query name. Never null. */ public String getQueryName() { return queryName; } /** * Returns a read-only view of this syncable data set's parameters. These * should correspond with the named parameters of the JPA named query this * syncable data set is tied to. * * @return a read-only map of the parameters in use with the query. Never null. */ public Map<String, Object> getParameters() { return params; } @Override public String toString() { return "SyncableDataSet [queryName=" + queryName + ", params=" + params + ", resultType=" + resultTypeFqcn + "]"; } }