001: /*
002: * $Header: /export/home/cvsroot/MyPersonalizerRepository/MyPersonalizer/Subsystems/Kernel/Sources/es/udc/mypersonalizer/kernel/model/query/executor/MetaPropertyResolver.java,v 1.1.1.1 2004/03/25 12:08:37 fbellas Exp $
003: * $Revision: 1.1.1.1 $
004: * $Date: 2004/03/25 12:08:37 $
005: *
006: * =============================================================================
007: *
008: * Copyright (c) 2003, The MyPersonalizer Development Group
009: * (http://www.tic.udc.es/~fbellas/mypersonalizer/index.html) at
010: * University Of A Coruņa
011: * All rights reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions are met:
015: *
016: * - Redistributions of source code must retain the above copyright notice,
017: * this list of conditions and the following disclaimer.
018: *
019: * - Redistributions in binary form must reproduce the above copyright notice,
020: * this list of conditions and the following disclaimer in the documentation
021: * and/or other materials provided with the distribution.
022: *
023: * - Neither the name of the University Of A Coruņa nor the names of its
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
028: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
029: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
030: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
031: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
032: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
033: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
034: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
035: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
036: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
037: * POSSIBILITY OF SUCH DAMAGE.
038: *
039: */
040: package es.udc.mypersonalizer.kernel.model.query.executor;
041:
042: import es.udc.mypersonalizer.kernel.log.Log;
043: import es.udc.mypersonalizer.kernel.log.LogManager;
044: import es.udc.mypersonalizer.kernel.log.LogNamingConventions;
045: import es.udc.mypersonalizer.kernel.model.metainfo.MetaProperty;
046: import es.udc.mypersonalizer.kernel.model.metainfo.MetaPropertyNotFoundException;
047: import es.udc.mypersonalizer.kernel.model.metainfo.MetaService;
048: import es.udc.mypersonalizer.kernel.model.metainfo.MetaServiceRegistrySingleton;
049: import es.udc.mypersonalizer.kernel.model.query.virtualmetainfo.LinkMetaPropertyAnnotationHelper;
050: import es.udc.mypersonalizer.kernel.model.query.virtualmetainfo.VirtualMetaPropertiesRegistrySingleton;
051: import es.udc.mypersonalizer.kernel.model.query.virtualmetainfo.VirtualMetaPropertyAnnotationHelper;
052:
053: /**
054: * Helper class with the purpose of resolving metaproperty names to
055: * <code>MetaProperty</code> objects. This can be done by fetching the
056: * root property of the <code>MetaService</code> with the given name, by
057: * finding the child metaproperty of the context (usually the last resolved
058: * metaproperty) or by looking the name up in the registry of
059: * <code>VirtualProperties</code>.
060: * <p>
061: * This class keeps state of the resolved properties to allow navigation
062: * from parent to children metaproperties, so the order of the calls to
063: * {@link #resolve(String)} is relevant.
064: *
065: * @see es.udc.mypersonalizer.kernel.model.query.executor.QueryExecutor
066: * @author Abel Muinho
067: * @since 1.0
068: */
069: public class MetaPropertyResolver {
070: private static final Log log = LogManager
071: .getLog(LogNamingConventions.MYPERSONALIZER);
072:
073: /** The information used for resolving name, kept from previous calls. */
074: private MetaPropertyResolverContext context;
075:
076: /** The reference to the virtual metaproperties registry. */
077: private static VirtualMetaPropertiesRegistrySingleton registry = VirtualMetaPropertiesRegistrySingleton
078: .getInstance();
079:
080: /**
081: * Default constructor which sets a <code>null</code> context.
082: */
083: public MetaPropertyResolver() {
084: this (null);
085: }
086:
087: /**
088: * Constructor setting an initial context based on the state of the given
089: * resolver.
090: * @param resolver the resolver whose state will be copied.
091: */
092: public MetaPropertyResolver(MetaPropertyResolver resolver) {
093: if (resolver == null) {
094: context = new MetaPropertyResolverContext();
095: } else {
096: context = (MetaPropertyResolverContext) resolver
097: .getContext().clone();
098: }
099: }
100:
101: /**
102: * Resolves the next <code>Step</code>'s name to a
103: * <code>MetaProperty</code>, or returns <code>null</code> if
104: * the name can't be resolved.
105: * @param name A property name to be resolved.
106: * @return the next <code>MetaProperty</code> or <code>null</code>.
107: */
108: public MetaProperty resolve(String name) {
109: MetaProperty metaProperty;
110: if (context.getCurrentMetaProperty() == null) {
111: /* No resolved MetaProperty, resolve a MetaService. */
112: MetaService metaService = MetaServiceRegistrySingleton
113: .getInstance().getMetaService(name);
114: metaProperty = (metaService != null) ? metaService
115: .getMetaRootProperty() : null;
116: } else {
117: try {
118: metaProperty = context.getCurrentMetaProperty()
119: .findMetaProperty(name);
120: } catch (MetaPropertyNotFoundException e) {
121: metaProperty = registry.getMetaProperty(context
122: .getUniqueName()
123: + '.' + name);
124: if (metaProperty != null) {
125: /* Avoid NullPointerException, the actual error reporting
126: * is performed later. */
127: String targetService = LinkMetaPropertyAnnotationHelper
128: .getTargetMetaService(metaProperty);
129: context.setUniqueName(targetService);
130: }
131: }
132: }
133:
134: /* Advance context to the just-resolved metaproperty, if exists. */
135: if (metaProperty != null) {
136: context.setCurrentMetaProperty(metaProperty);
137: if (!VirtualMetaPropertyAnnotationHelper
138: .isVirtual(metaProperty)) {
139: context.appendName(name);
140: }
141: } else {
142: log.write("Property '" + name
143: + "' not found. Current context = " + context,
144: null, MetaPropertyResolver.class);
145: }
146:
147: return metaProperty;
148: }
149:
150: /**
151: * Obtains the current context metaproperty, which will be used by the
152: * resolver on the next call to <code>resolve()</code>.
153: * @return the context metaproperty.
154: */
155: protected MetaPropertyResolverContext getContext() {
156: return context;
157: }
158: }
159:
160: /**
161: * Package-visible class representing the state of the resolver.
162: * <p>
163: * This class should not be used outside the <code>MetaPropertyResolver</code>.
164: *
165: * @author Abel Muinho
166: * @since 1.0
167: */
168: class MetaPropertyResolverContext implements Cloneable {
169: private StringBuffer uniqueName = new StringBuffer(64);
170: private MetaProperty currentMetaProperty;
171:
172: /**
173: * Return the unique name generated from the resolution calls.
174: * <p>
175: * Unique names are generated like scoped names, but starting
176: * with the service id instead of the root property name.
177: *
178: * @return the unique name,
179: */
180: public String getUniqueName() {
181: return uniqueName.toString();
182: }
183:
184: /**
185: * Appends a name to the unique name. It will be appended at the end
186: * with a preceding dot.
187: * @param name the name to append.
188: */
189: public void appendName(String name) {
190: if (uniqueName.length() > 0) {
191: uniqueName.append('.');
192: }
193: uniqueName.append(name);
194: }
195:
196: /**
197: * Sets the unique name <code>StringBuffer</code>.
198: * @param uniqueName the unique name.
199: */
200: protected void setUniqueName(StringBuffer uniqueName) {
201: this .uniqueName = uniqueName;
202: }
203:
204: /**
205: * Sets the unique name <code>StringBuffer</code> with an initial value.
206: * @param initialValue the unique name initial value.
207: */
208: protected void setUniqueName(String initialValue) {
209: uniqueName = new StringBuffer(Math.max(64, initialValue
210: .length()));
211: uniqueName.append(initialValue);
212: }
213:
214: /**
215: * Obtains the current metaproperty in the context.
216: * @return the current metaproperty.
217: */
218: public MetaProperty getCurrentMetaProperty() {
219: return currentMetaProperty;
220: }
221:
222: /**
223: * Sets the current metaproperty.
224: * @param currentMetaProperty the new current metaproperty.
225: */
226: public void setCurrentMetaProperty(MetaProperty currentMetaProperty) {
227: this .currentMetaProperty = currentMetaProperty;
228: }
229:
230: public Object clone() {
231: MetaPropertyResolverContext result = new MetaPropertyResolverContext();
232: result.setCurrentMetaProperty(this .getCurrentMetaProperty());
233: result.setUniqueName(new StringBuffer(getUniqueName()));
234: return result;
235: }
236:
237: public String toString() {
238: return "{currentMetaProperty = '"
239: + (currentMetaProperty != null ? currentMetaProperty
240: .getSimpleName() : "null")
241: + "', uniqueName = '" + uniqueName + "'}";
242: }
243: }
|