blob: b12067d1bba27a8d1d62fd3c51304ca3d5590ccb [file] [log] [blame]
/***************************************************************************************************
* Copyright (c) 2003, 2004 IBM Corporation and others. All rights reserved. This program and the
* accompanying materials are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: IBM Corporation - initial API and implementation
**************************************************************************************************/
/*
* Created on Sep 21, 2003
*
*/
package org.eclipse.wst.common.internal.emf.resource;
import org.eclipse.emf.ecore.EObject;
/*
* Translator filters can be used to differentiate between Object and Attribute Translators without
* breaking them out into seperate data structures. The Filter will rely on the underlying data
* structure used to store the children of the given Translator.
*
* getNextChild() will return null when no other translators of the given genre are available.
*
* The processing hints which are created and then passed to getNext*Translator() store information
* that needs to be persisted between calls. The createProcessingHints() will create a properly
* initialized array. The constants NEXT_START_HINT_INDX and MODE_HINT_INDX provide pointers into
* the array for the NEXT_START position and the proper mode to operate in
* (STANDARD_TRANSLATORS_MODE or
*
*/
public abstract class TranslatorFilter {
protected final Translator translator;
protected final int version;
public static final int NEXT_START_HINT_INDX = 0;
public static final int MODE_HINT_INDX = 1;
public static final int STANDARD_TRANSLATORS_MODE = 0;
public static final int VARIABLE_TRANSLATORS_MODE = 1;
/*
* These TranslatorFilters are used in a stateless mode. Only their scanNextTranslator() methods
* will be invoked
*/
private static final TranslatorFilter objectTranslatorFilter = new ObjectTranslatorFilter(null, -1);
private static final TranslatorFilter attributeTranslatorFilter = new AttributeTranslatorFilter(null, -1);
protected int mode = STANDARD_TRANSLATORS_MODE;
protected int index = -1;
protected Translator cachedPeekAheadTranslator = null;
public TranslatorFilter(Translator trans, int version) {
this.translator = trans;
this.version = version;
}
/**
* Calling peek twice will advance the current child
*/
public Translator peekNextChild(EObject target) {
cachedPeekAheadTranslator = getNextChild(target);
return cachedPeekAheadTranslator;
}
/**
* getNextChild() will return null when no other translators of the given genre are available.
*/
public Translator getNextChild(EObject target) {
Translator result = null;
if (cachedPeekAheadTranslator != null) {
result = cachedPeekAheadTranslator;
cachedPeekAheadTranslator = null;
return result;
}
int found = 0;
Translator children[] = null;
switch (mode) {
case STANDARD_TRANSLATORS_MODE :
children = this.translator.getChildren(target, this.version);
/* Look for the next Attribute Translator */
found = scanNextTranslator(children, this.index);
if (found >= 0) {
/*
* If found, (1) update the result, (2) update the index so we can skip ahead on
* the next invocation (3) escape the VARIABLE_TRANSLATORS processing
*/
result = children[found];
this.index = found;
break;
}
/*
* Reset the index. DO NOT BREAK. Allow entry into VARIABLE_TRANSLATORS case
*/
this.index = -1;
/*
* update the mode to VARIABLE_TRANSLATORS so we can skip to it directly next time
*/
this.mode = VARIABLE_TRANSLATORS_MODE;
case VARIABLE_TRANSLATORS_MODE :
children = this.translator.getVariableChildren(target, this.version);
found = scanNextTranslator(children, this.index);
if (found >= 0) {
/*
* If found, (1) update the result, (2) update the index so we can skip ahead on
* the next invocation
*/
result = children[found];
this.index = found;
}
}
return result;
}
public static final int[] createProcessingHints() {
return new int[]{-1, STANDARD_TRANSLATORS_MODE};
}
public static final Translator getNextAttributeTranslator(Translator translator, int startHint, int[] nextHint, EObject target, int version) {
return TranslatorFilter.getNextChild(translator, startHint, nextHint, target, version, attributeTranslatorFilter);
}
public static final Translator getNextObjectTranslator(Translator translator, int startHint, int[] nextHint, EObject target, int version) {
return TranslatorFilter.getNextChild(translator, startHint, nextHint, target, version, objectTranslatorFilter);
}
/**
* getNextChild() takes hints on where to begin in the children array of the given Translator.
* When it finds the translator, it will update the hints array with the start hint for the next
* invocation(hints[0]) and when necessary it will use update the mode (hints[1]) to either
* STANDARD_TRANSLATORS or VARIABLE_TRANSLATORS.
*
* @param translator
* @param startHint
* @param hints
* a two-element array: hints[0] will be updated with the next startHint and hints[1]
* will be used to store the mode.
* @param target
* @param version
* @param translatorFilter
* @return
*/
public static final Translator getNextChild(Translator translator, int startHint, int[] hints, EObject target, int version, TranslatorFilter translatorFilter) {
Translator result = null;
int index = startHint;
Translator children[] = null;
switch (hints[MODE_HINT_INDX]) {
case STANDARD_TRANSLATORS_MODE :
children = translator.getChildren(target, version);
if (children != null && startHint < children.length) {
/* Look for the next Attribute Translator */
index = translatorFilter.scanNextTranslator(children, index);
if (index >= 0) {
/*
* If found, (1) update the result, (2) update the index so we can skip
* ahead on the next invocation (3) escape the VARIABLE_TRANSLATORS
* processing
*/
result = children[index];
break;
}
/*
* DO NOT BREAK we will default to VARIABLE TRANSLATORS MODE so we must reset
* the startHint appropriately
*/
startHint = -1;
}
case VARIABLE_TRANSLATORS_MODE :
hints[MODE_HINT_INDX] = VARIABLE_TRANSLATORS_MODE;
/*
* Reset the index.
*/
index = startHint;
children = translator.getVariableChildren(target, version);
if (children != null && children.length > 0 && startHint < children.length) {
index = translatorFilter.scanNextTranslator(children, index);
result = (index >= 0) ? children[index] : null;
}
}
hints[NEXT_START_HINT_INDX] = (result == null && children != null) ? children.length : index;
return result;
}
public abstract int scanNextTranslator(Translator[] children, int start);
/**
* @return
*/
public int getIndex() {
return index;
}
/**
* @return
*/
public int getMode() {
return mode;
}
}