/***************************************************************** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.cayenne.query; import org.apache.cayenne.CayenneRuntimeException; import org.apache.cayenne.ObjectId; import org.apache.cayenne.exp.Expression; import org.apache.cayenne.exp.ExpressionFactory; import org.apache.cayenne.map.EntityResolver; import org.apache.cayenne.map.ObjEntity; import org.apache.cayenne.reflect.ClassDescriptor; import org.apache.cayenne.util.Util; /** * A query that matches zero or one object or data row corresponding to the ObjectId. Used * internally by Cayenne to lookup objects by id. Notice that cache policies of * ObjectIdQuery are different from generic {@link QueryMetadata} cache policies. * ObjectIdQuery is special - it is the only query that can be done against Cayenne main * cache, thus cache handling is significantly different from all other of the queries. * * @since 1.2 */ public class ObjectIdQuery extends IndirectQuery { // TODO: Andrus, 2/18/2006 - reconcile this with QueryMetadata cache policies public static final int CACHE = 1; public static final int CACHE_REFRESH = 2; public static final int CACHE_NOREFRESH = 3; protected ObjectId objectId; protected int cachePolicy; protected boolean fetchingDataRows; protected transient EntityResolver metadataResolver; protected transient QueryMetadata metadata; // needed for hessian serialization @SuppressWarnings("unused") private ObjectIdQuery() { this.cachePolicy = CACHE_REFRESH; } /** * Creates a refreshing ObjectIdQuery. */ public ObjectIdQuery(ObjectId objectID) { this(objectID, false, CACHE_REFRESH); } /** * Creates a new ObjectIdQuery. */ public ObjectIdQuery(ObjectId objectId, boolean fetchingDataRows, int cachePolicy) { if (objectId == null) { throw new NullPointerException("Null objectID"); } this.objectId = objectId; this.cachePolicy = cachePolicy; this.fetchingDataRows = fetchingDataRows; } /** * Returns query metadata object. */ // return metadata without creating replacement, as it is not always possible to // create replacement (e.g. temp ObjectId). @Override public QueryMetadata getMetaData(final EntityResolver resolver) { // caching metadata as it may be accessed multiple times (at a DC and DD level) if (metadata == null || metadataResolver != resolver) { this.metadata = new DefaultQueryMetadata() { @Override public ClassDescriptor getClassDescriptor() { return resolver.getClassDescriptor(objectId.getEntityName()); } @Override public ObjEntity getObjEntity() { return getClassDescriptor().getEntity(); } @Override public boolean isFetchingDataRows() { return fetchingDataRows; } }; this.metadataResolver = resolver; } return metadata; } public ObjectId getObjectId() { return objectId; } @Override protected Query createReplacementQuery(EntityResolver resolver) { if (objectId == null) { throw new CayenneRuntimeException("Can't resolve query - objectId is null."); } if (objectId.isTemporary() && !objectId.isReplacementIdAttached()) { throw new CayenneRuntimeException("Can't build a query for temporary id: %s", objectId); } SelectQuery<Object> query = new SelectQuery<>(objectId.getEntityName(), ExpressionFactory .matchAllDbExp(objectId.getIdSnapshot(), Expression.EQUAL_TO)); // if we got to the point of fetch, always force refresh.... query.setFetchingDataRows(fetchingDataRows); return query; } public int getCachePolicy() { return cachePolicy; } public boolean isFetchMandatory() { return cachePolicy == CACHE_REFRESH; } public boolean isFetchAllowed() { return cachePolicy != CACHE_NOREFRESH; } public boolean isFetchingDataRows() { return fetchingDataRows; } /** * Overrides toString() outputting a short string with query class and ObjectId. */ @Override public String toString() { return Util.stripPackageName(getClass().getName()) + ":" + objectId; } /** * An object is considered equal to this query if it is also a ObjectIdQuery with * an equal ObjectId. */ @Override public boolean equals(Object object) { if (this == object) { return true; } if (!(object instanceof ObjectIdQuery)) { return false; } ObjectIdQuery query = (ObjectIdQuery) object; return Util.nullSafeEquals(objectId, query.getObjectId()); } /** * Implements a standard hashCode contract considering custom 'equals' implementation. */ @Override public int hashCode() { return (objectId != null) ? objectId.hashCode() : 11; } }