diff options
author | Pascal Filion | 2012-12-19 18:54:24 +0000 |
---|---|---|
committer | Pascal Filion | 2012-12-19 18:54:24 +0000 |
commit | e514223377f00da0a8c16795e71df0f9e00425d1 (patch) | |
tree | b03054438797605b16eb83f870cd92f228ad9995 | |
parent | 2c2c3d7e07abd8a5e0805ad3423be11ae46b01ba (diff) | |
download | webtools.dali-e514223377f00da0a8c16795e71df0f9e00425d1.tar.gz webtools.dali-e514223377f00da0a8c16795e71df0f9e00425d1.tar.xz webtools.dali-e514223377f00da0a8c16795e71df0f9e00425d1.zip |
Removed code that is now in Hermes, added content assist extension for table names, columns, enum types, enum constants.
11 files changed, 409 insertions, 931 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/DefaultContentAssistExtension.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/DefaultContentAssistExtension.java new file mode 100644 index 0000000000..b3ee2cd362 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/DefaultContentAssistExtension.java @@ -0,0 +1,253 @@ +/******************************************************************************* + * Copyright (c) 2012 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Oracle - initial API and implementation + * + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.jpql; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterable.FilteringIterable; +import org.eclipse.jpt.common.utility.internal.iterable.TransformationIterable; +import org.eclipse.jpt.jpa.core.JpaProject; +import org.eclipse.jpt.jpa.db.Database; +import org.eclipse.jpt.jpa.db.Schema; +import org.eclipse.jpt.jpa.db.Table; +import org.eclipse.persistence.jpa.jpql.ContentAssistExtension; +import org.eclipse.persistence.jpa.jpql.ContentAssistProposals.ClassType; +import org.eclipse.persistence.jpa.jpql.ExpressionTools; + +/** + * This extension can be used to provide additional support to JPQL content assist that is outside + * the scope of providing proposals related to JPA metadata. It adds support for providing + * suggestions related to class names, enum constants, table names, column names. + * <p> + * Note: This will only be invoked if the JPQL grammar supports it, generic JPA does not. + * + * @version 3.3 + * @since 3.3 + * @author Pascal Filion + */ +public class DefaultContentAssistExtension implements ContentAssistExtension { + + /** + * The JPA project is necessary to give access to the additional information. + */ + private JpaProject jpaProject; + + /** + * The character used to quote a table name, which is used to case-sensitive or containing + * special characters. + */ + private static final char TABLE_QUALIFIER = '`'; + + /** + * Creates a new <code>DefaultContentAssistExtension</code>. + * + * @param jpaProject The JPA project is necessary to give access to the additional information + */ + public DefaultContentAssistExtension(JpaProject jpaProject) { + super(); + this.jpaProject = jpaProject; + } + + protected boolean acceptClass(IType type, + String className, + ClassType classType, + String prefix, + boolean hasDot) throws Exception { + + // Filter first on the name because it's a lot less expensive + // than asking question on IType + if (!isClassFiltered(className, prefix, hasDot)) { + return !type.isAnonymous() && + (classType == ClassType.INSTANTIABLE) ? type.isClass() : type.isEnum() && + !type.isMember(); + } + + return false; + } + + /** + * {@inheritDoc} + */ + public Iterable<String> classNames(String prefix, ClassType classType) { + + IJavaProject javaProject = jpaProject.getJavaProject(); + Set<String> classNames = new HashSet<String>(); + boolean emptyPrefix = (prefix.length() == 0); + int index = !emptyPrefix ? prefix.lastIndexOf('.') : -1; + boolean hasDot = (index > -1); + + // Note: In order to increase performance by preventing array creation and filtering, + // IParent.getChildren() is used, then a simple check is performed on the element type + try { + + // Traverse the packages + for (IPackageFragment packageFragment : javaProject.getPackageFragments()) { + String packageName = packageFragment.getElementName(); + + // Filter the package out if the prefix has a dot, + // match the beginning of the prefix up to the last dot + boolean packageAccepted = !hasDot || packageName.regionMatches(true, 0, prefix, 0, index); + + if (packageAccepted) { + + // Traverse the classes within the package + for (IJavaElement javaElement : packageFragment.getChildren()) { + + switch (javaElement.getElementType()) { + + // Java source files + case IJavaElement.COMPILATION_UNIT: { + + ICompilationUnit compilationUnit = (ICompilationUnit) javaElement; + + for (IJavaElement cuChild : compilationUnit.getChildren()) { + + // Class definition + if (cuChild.getElementType() == IJavaElement.TYPE) { + IType type = (IType) cuChild; + String className = type.getFullyQualifiedName(); + + // Filter out the class if required + // NOTE: An empty prefix will not filter anonymous or member classes, + // to do so, we need to use what the Java content assist uses + // otherwise it takes too long to calculate the valid classes + if (emptyPrefix || acceptClass(type, className, classType, prefix, hasDot)) { + classNames.add(className); + } + } + } + + break; + } + + // Java class files + case IJavaElement.CLASS_FILE: { + + IClassFile classFile = (IClassFile) javaElement; + IType type = classFile.getType(); + String className = type.getFullyQualifiedName(); + + // Filter out the class if required + // NOTE: An empty prefix will not filter anonymous or member classes, + // to do so, we need to use what the Java content assist uses + // otherwise it takes too long to calculate the valid classes + if (emptyPrefix || acceptClass(type, className, classType, prefix, hasDot)) { + classNames.add(className); + } + + break; + } + } + } + } + } + } + catch (Exception e) { + // Just ignore + } + + return classNames; + } + + /** + * {@inheritDoc} + */ + public Iterable<String> columnNames(String tableName, final String prefix) { + + Schema schema = getSchema(); + + if (schema == null) { + return Collections.emptyList(); + } + + Table table = schema.getTableNamed(tableName); + + if (table == null) { + return Collections.emptyList(); + } + + if (prefix.length() == 0) { + return table.getSortedColumnIdentifiers(); + } + + return new FilteringIterable<String>(table.getSortedColumnIdentifiers()) { + @Override + protected boolean accept(String name) { + return ExpressionTools.startWithIgnoreCase(name, prefix); + } + }; + } + + protected Schema getSchema() { + Database database = jpaProject.getDataSource().getDatabase(); + return (database == null) ? null : database.getDefaultSchema(); + } + + protected boolean isClassFiltered(String className, String prefix, boolean hasDot) { + + // The prefix does not have a dot, it's not a package name, retrieve the short class name + if (!hasDot) { + int index = className.lastIndexOf('.'); + if (index > -1) { + className = className.substring(index + 1, className.length()); + } + } + + if (className.lastIndexOf('$') > -1) { + return true; + } + + // Filter using the prefix + return !StringTools.startsWithIgnoreCase(className, prefix); + } + + protected Iterable<String> tableNames(Schema schema) { + return new TransformationIterable<String, String>(schema.getSortedTableIdentifiers()) { + @Override + protected String transform(String tableName) { + if (tableName.charAt(0) == TABLE_QUALIFIER) { + tableName = StringTools.undelimit(tableName, 1); + } + return tableName; + } + }; + } + + /** + * {@inheritDoc} + */ + public Iterable<String> tableNames(final String prefix) { + + Schema schema = getSchema(); + + if (schema == null) { + return Collections.emptyList(); + } + + return new FilteringIterable<String>(tableNames(schema)) { + @Override + protected boolean accept(String tableName) { + return StringTools.startsWithIgnoreCase(tableName, prefix); + } + }; + } +}
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/JpaJpqlQueryHelper.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/JpaJpqlQueryHelper.java index d2f051fb13..ea2c5b075c 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/JpaJpqlQueryHelper.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/JpaJpqlQueryHelper.java @@ -29,12 +29,15 @@ import org.eclipse.jpt.jpa.core.jpql.spi.IManagedTypeBuilder; import org.eclipse.jpt.jpa.core.jpql.spi.JpaManagedTypeProvider; import org.eclipse.jpt.jpa.core.jpql.spi.JpaQuery; import org.eclipse.persistence.jpa.jpql.AbstractJPQLQueryHelper; +import org.eclipse.persistence.jpa.jpql.ContentAssistExtension; +import org.eclipse.persistence.jpa.jpql.ContentAssistProposals; import org.eclipse.persistence.jpa.jpql.ExpressionTools; import org.eclipse.persistence.jpa.jpql.JPQLQueryProblem; import org.eclipse.persistence.jpa.jpql.parser.JPQLGrammar; import org.eclipse.persistence.jpa.jpql.spi.IManagedTypeProvider; import org.eclipse.persistence.jpa.jpql.spi.IMappingBuilder; import org.eclipse.persistence.jpa.jpql.spi.IQuery; +import org.eclipse.persistence.jpa.jpql.util.XmlEscapeCharacterConverter; import org.eclipse.wst.validation.internal.provisional.core.IMessage; /** @@ -56,13 +59,15 @@ import org.eclipse.wst.validation.internal.provisional.core.IMessage; * to solicit feedback from pioneering adopters on the understanding that any code that uses this * API will almost certainly be broken (repeatedly) as the API evolves. * - * @version 3.2 + * @version 3.3 * @since 3.0 * @author Pascal Filion */ @SuppressWarnings("nls") public abstract class JpaJpqlQueryHelper extends AbstractJPQLQueryHelper { + private JpaProject jpaProject; + /** * Caches the provider in order to prevent recreating the SPI representation of the JPA artifacts * more than once. @@ -79,41 +84,20 @@ public abstract class JpaJpqlQueryHelper extends AbstractJPQLQueryHelper { } /** - * TODO: TO REMOVE ONCE THE NEXT ECLIPSE HERMES MILESTONE IS AVAILABLE. + * {@inheritDoc} */ - private static void repositionJava(String query, int[] positions) { - - if ((query == null) || (query.length() == 0)) { - return; - } + @Override + public ContentAssistProposals buildContentAssistProposals(int position) { + return super.buildContentAssistProposals(position, buildContentAssistProposalsHelper()); + } - StringBuilder sb = new StringBuilder(query); - - for (int index = 0, count = sb.length(); index < count; index++) { - - char character = sb.charAt(index); - - switch (character) { - case '\b': case '\t': case '\n': - case '\f': case '\r': case '\"': - case '\\': case '\0': case '\1': - case '\2': case '\3': case '\4': - case '\5': case '\6': case '\7': { - - // Translate both positions because the special - // character is written with its escape character - if (index < positions[0]) { - positions[0]++; - positions[1]++; - } - // Only translate the end position because the start - // position is before the current index - else if (index < positions[1]) { - positions[1]++; - } - } - } - } + /** + * Creates the helper that will be used to extend the support for JPQL content assist. + * + * @return A new instance of {@link GenericContentAssistProposalHelper} + */ + protected ContentAssistExtension buildContentAssistProposalsHelper() { + return new DefaultContentAssistExtension(jpaProject); } /** @@ -164,10 +148,7 @@ public abstract class JpaJpqlQueryHelper extends AbstractJPQLQueryHelper { } // Reposition the cursor so it's correctly positioned in the non-escaped JPQL query - // TODO: UPDATE ONCE THE NEXT ECLIPSELINK HERMES 2.5 MILESTONE IS AVAILABLE - // ExpressionTools.reposition(parsedJpqlQuery, positions, jpqlQuery); - positions[0] = ExpressionTools.repositionCursor(parsedJpqlQuery, positions[0], jpqlQuery); - positions[1] = ExpressionTools.repositionCursor(parsedJpqlQuery, positions[1], jpqlQuery); + ExpressionTools.reposition(parsedJpqlQuery, positions, jpqlQuery); // Now add the leading offset positions[0] += offset; @@ -176,13 +157,9 @@ public abstract class JpaJpqlQueryHelper extends AbstractJPQLQueryHelper { // Now convert the adjusted positions once again to be in the actual JPQL query that is // found in the document, i.e. that may contain escape characters if (escapeType == EscapeType.JAVA) { - - // TODO: UPDATE ONCE THE NEXT ECLIPSELINK HERMES 2.5 MILESTONE IS AVAILABLE - // ExpressionTools.repositionJava(actualJpqlQuery, positions); - repositionJava(actualJpqlQuery, positions); + ExpressionTools.repositionJava(actualJpqlQuery, positions); } else if (escapeType == EscapeType.XML) { - // TODO: UPDATE ONCE THE NEXT ECLIPSELINK HERMES 2.5 MILESTONE IS AVAILABLE XmlEscapeCharacterConverter.reposition(actualJpqlQuery, positions); } @@ -192,8 +169,7 @@ public abstract class JpaJpqlQueryHelper extends AbstractJPQLQueryHelper { /** * Creates a new {@link IMessage} for the given {@link JPQLQueryProblem}. * - * @param namedQuery The model object for which a new {@link IMessage} is creating describing the - * problem + * @param namedQuery The model object for which a new {@link IMessage} is creating describing the problem * @param problem The {@link JPQLQueryProblem problem} that was found in the JPQL query, which is * either a grammatical or semantic problem * @param textRanges The list of {@link TextRange} objects that represents the JPQL query string @@ -316,8 +292,10 @@ public abstract class JpaJpqlQueryHelper extends AbstractJPQLQueryHelper { */ public void setQuery(NamedQuery namedQuery, String actualQuery) { + jpaProject = namedQuery.getJpaProject(); + if (managedTypeProvider == null) { - managedTypeProvider = buildProvider(namedQuery.getJpaProject(), namedQuery.getPersistenceUnit()); + managedTypeProvider = buildProvider(jpaProject, namedQuery.getPersistenceUnit()); } IQuery query = new JpaQuery(managedTypeProvider, namedQuery, actualQuery); @@ -326,8 +304,9 @@ public abstract class JpaJpqlQueryHelper extends AbstractJPQLQueryHelper { protected boolean shouldValidate(NamedQuery namedQuery) { return ObjectTools.notEquals( - getValidationPreference(namedQuery), - JpaPreferences.PROBLEM_IGNORE); + getValidationPreference(namedQuery), + JpaPreferences.PROBLEM_IGNORE + ); } /** diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/XmlEscapeCharacterConverter.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/XmlEscapeCharacterConverter.java deleted file mode 100644 index 321916ba3a..0000000000 --- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/XmlEscapeCharacterConverter.java +++ /dev/null @@ -1,657 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 Oracle. All rights reserved. - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 - * which accompanies this distribution. - * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Oracle - initial API and implementation - * - ******************************************************************************/ -package org.eclipse.jpt.jpa.core.jpql; - -import java.util.HashMap; -import java.util.Map; - -/** - * TODO: TO DELETE ONCE THE NEXT ECLIPSELINK HERMES 2.5 MILESTONE IS AVAILABLE. - * - * @version 2.5 - * @since 2.5 - * @author Pascal Filion - */ -@SuppressWarnings("nls") -public final class XmlEscapeCharacterConverter { - - /** - * The entity name for ampersand: <b>&</b>. - */ - public static final String AMPERSAND_ENTITY_NAME = "&"; - - /** - * The entity name for apostrophe: <b>'</b>. - */ - public static final String APOSTROPHE_ENTITY_NAME = "'"; - - /** - * The map of symbol mapped to the unicode character. - */ - private static final Map<String, String> dictionary = buildDictionary(); - - /** - * The entity name for greater-than symbol: <b>></b>. - */ - public static final String GREATER_THAN_ENTITY_NAME = ">"; - - /** - * The entity name for less-than symbol: <b><</b>. - */ - public static final String LESS_THAN_ENTITY_NAME = "<"; - - /** - * The entity name for quotation mark: <b>"</b>. - */ - public static final String QUOTATION_MARK_NAME = """; - - /** - * Cannot instantiate <code>XmlEscapeCharacterConverter</code>. - */ - private XmlEscapeCharacterConverter() { - super(); - } - - private static Map<String, String> buildDictionary() { - - Map<String, String> dictionary = new HashMap<String, String>(); - - // Reserved characters - dictionary.put("quot", "\""); // Quotation Mark - dictionary.put("apos", "'"); // Apostrophe - dictionary.put("amp", "&"); // Ampersand - dictionary.put("lt", "<"); // Less Than Symbol - dictionary.put("gt", ">"); // Greater Than Symbol - - // ISO-8859-1 symbols - dictionary.put("nbsp", "\u00A0"); // Nonbreaking space - dictionary.put("iexcl", "\u00A1"); // Inverted Exclamation Point - dictionary.put("cent", "\u00A2"); // Cent Sign - dictionary.put("pound", "\u00A3"); // Pound Sterling - dictionary.put("curren", "\u00A4"); // General Currency Sign - dictionary.put("yen", "\u00A5"); // Yen Sign - dictionary.put("brvbar", "\u00A6"); // Broken Vertical Bar - dictionary.put("sect", "\u00A7"); // Section Sign - dictionary.put("uml", "\u00A8"); // Umlaut - dictionary.put("copy", "\u00A9"); // Copyright - dictionary.put("ordf", "\u00AA"); // Feminine Ordinal - dictionary.put("laquo", "\u00AB"); // Left Angle Quote - dictionary.put("not", "\u00AC"); // Not Sign - dictionary.put("shy", "\u00AD"); // Soft Hyphen - dictionary.put("reg", "\u00AE"); // Registered Trademark - dictionary.put("macr", "\u00AF"); // Macron Accent - dictionary.put("deg", "\u00B0"); // Degree Sign - dictionary.put("plusmn", "\u00B1"); // Plus or Minus - dictionary.put("sup2", "\u00B2"); // Superscript Two - dictionary.put("sup3", "\u00B3"); // Superscript Three - dictionary.put("acute", "\u00B4"); // Acute Accent - dictionary.put("micro", "\u00B5"); // Micro Sign - dictionary.put("para", "\u00B6"); // Paragraph Sign - dictionary.put("middot", "\u00B7"); // Middle Dot - dictionary.put("cedil", "\u00B8"); // Cedilla - dictionary.put("sup1", "\u00B9"); // Superscript One - dictionary.put("ordm", "\u00BA"); // Masculine Ordinal - dictionary.put("raquo", "\u00BB"); // Right Angle Quote - dictionary.put("frac14", "\u00BC"); // Fraction One-Forth - dictionary.put("frac12", "\u00BD"); // Fraction One-Half - dictionary.put("frac34", "\u00BE"); // Fraction Three-Fourths - dictionary.put("iquest", "\u00BF"); // Inverted Question Mark - dictionary.put("times", "\u00D7"); // Multiplication - dictionary.put("divide", "\u00F7"); // Division - - // ISO-8859-1 characters - dictionary.put("Agrave", "\u00C0"); // Latin capital letter A with grave accent - dictionary.put("Aacute", "\u00C1"); // Latin capital letter A with acute accent - dictionary.put("Acirc", "\u00C2"); // Latin capital letter A with circumflex - dictionary.put("Atilde", "\u00C3"); // Latin capital letter A with tilde - dictionary.put("Auml", "\u00C4"); // Latin capital letter A with diaeresis - dictionary.put("Aring", "\u00C5"); // Latin capital letter A with ring above - dictionary.put("AElig", "\u00C6"); // Latin capital letter AE - dictionary.put("Ccedil", "\u00C7"); // Latin capital letter C with cedilla - dictionary.put("Egrave", "\u00C8"); // Latin capital letter E with grave accent - dictionary.put("Eacute", "\u00C9"); // Latin capital letter E with acute accent - dictionary.put("Ecirc", "\u00CA"); // Latin capital letter E with circumflex - dictionary.put("Euml", "\u00CB"); // Latin capital letter E with diaeresis - dictionary.put("Igrave", "\u00CC"); // Latin capital letter I with grave accent - dictionary.put("Iacute", "\u00CD"); // Latin capital letter I with acute accent - dictionary.put("Icirc", "\u00CE"); // Latin capital letter I with circumflex - dictionary.put("Iuml", "\u00CF"); // Latin capital letter I with diaeresis - dictionary.put("ETH", "\u00D0"); // Latin capital letter Eth - dictionary.put("Ntilde", "\u00D1"); // Latin capital letter N with tilde - dictionary.put("Ograve", "\u00D2"); // Latin capital letter O with grave accent - dictionary.put("Oacute", "\u00D3"); // Latin capital letter O with acute accent - dictionary.put("Ocirc", "\u00D4"); // Latin capital letter O with circumflex - dictionary.put("Otilde", "\u00D5"); // Latin capital letter O with tilde - dictionary.put("Ouml", "\u00D6"); // Latin capital letter O with diaeresis - dictionary.put("Oslash", "\u00D8"); // Latin capital letter O with stroke - dictionary.put("Ugrave", "\u00D9"); // Latin capital letter U with grave accent - dictionary.put("Uacute", "\u00DA"); // Latin capital letter U with acute accent - dictionary.put("Ucirc", "\u00DB"); // Latin capital letter U with circumflex - dictionary.put("Uuml", "\u00DC"); // Latin capital letter U with diaeresis - dictionary.put("Yacute", "\u00DD"); // Latin capital letter Y with acute accent - dictionary.put("THORN", "\u00DE"); // Latin capital letter THORN - dictionary.put("szlig", "\u00DF"); // Latin small letter sharp s - dictionary.put("agrave", "\u00E0"); // Latin small letter a with grave accent - dictionary.put("aacute", "\u00E1"); // Latin small letter a with acute accent - dictionary.put("acirc", "\u00E2"); // Latin small letter a with circumflex - dictionary.put("atilde", "\u00E3"); // Latin small letter a with tilde - dictionary.put("auml", "\u00E4"); // Latin small letter a with diaeresis - dictionary.put("aring", "\u00E5"); // Latin small letter a with ring above - dictionary.put("aelig", "\u00E6"); // Latin small letter ae - dictionary.put("ccedil", "\u00E7"); // Latin small letter c with cedilla - dictionary.put("egrave", "\u00E8"); // Latin small letter e with grave accent - dictionary.put("eacute", "\u00E9"); // Latin small letter e with acute accent - dictionary.put("ecirc", "\u00EA"); // Latin small letter e with circumflex - dictionary.put("euml", "\u00EB"); // Latin small letter e with diaeresis - dictionary.put("igrave", "\u00EC"); // Latin small letter i with grave accent - dictionary.put("iacute", "\u00ED"); // Latin small letter i with acute accent - dictionary.put("icirc", "\u00EE"); // Latin small letter i with circumflex - dictionary.put("iuml", "\u00EF"); // Latin small letter i with diaeresis - dictionary.put("eth", "\u00F0"); // Latin small letter eth - dictionary.put("ntilde", "\u00F1"); // Latin small letter n with tilde - dictionary.put("ograve", "\u00F2"); // Latin small letter o with grave accent - dictionary.put("oacute", "\u00F3"); // Latin small letter o with acute accent - dictionary.put("ocirc", "\u00F4"); // Latin small letter o with circumflex - dictionary.put("otilde", "\u00F5"); // Latin small letter o with tilde - dictionary.put("ouml", "\u00F6"); // Latin small letter o with diaeresis - dictionary.put("oslash", "\u00F8"); // Latin small letter o with stroke - dictionary.put("ugrave", "\u00F9"); // Latin small letter u with grave accent - dictionary.put("uacute", "\u00FA"); // Latin small letter u with acute accent - dictionary.put("ucirc", "\u00FB"); // Latin small letter u with circumflex - dictionary.put("uuml", "\u00FC"); // Latin small letter u with diaeresis - dictionary.put("yacute", "\u00FD"); // Latin small letter y with acute accent - dictionary.put("thorn", "\u00FE"); // Latin small letter thorn - dictionary.put("yuml", "\u00FF"); // Latin small letter y with diaeresis - - // Math Symbols - dictionary.put("forall", "\u2200"); // For all - dictionary.put("part", "\u2202"); // Partial differential - dictionary.put("exist", "\u2203"); // There exists - dictionary.put("empty", "\u2205"); // Empty set; Null Set; Diameter - dictionary.put("nabla", "\u2207"); // Nabla; Backward difference - dictionary.put("isin", "\u2208"); // Element of - dictionary.put("notin", "\u2209"); // Not an element of - dictionary.put("ni", "\u220B"); // Contains as member - dictionary.put("prod", "\u220F"); // N-ary product; Product sign - dictionary.put("sum", "\u2211"); // N-ary sumation - dictionary.put("minus", "\u2212"); // Minus sign - dictionary.put("lowast", "\u2217"); // Asterisk operator - dictionary.put("radic", "\u221A"); // Square root; Radical sign - dictionary.put("prop", "\u221D"); // Proportional to - dictionary.put("infin", "\u221E"); // Infinity - dictionary.put("ang", "\u2220"); // Angle - dictionary.put("and", "\u2227"); // Logical and; Wedge - dictionary.put("or", "\u2228"); // Logical or; Vee - dictionary.put("cap", "\u2229"); // Intersection; Cap - dictionary.put("cup", "\u222A"); // Union; Cup - dictionary.put("int", "\u222B"); // Integral - dictionary.put("there4", "\u2234"); // Therefore - dictionary.put("sim", "\u223C"); // Tilde operator; Varies with; Similar to - dictionary.put("cong", "\u2245"); // Approximately equal to - dictionary.put("asymp", "\u2248"); // Almost equal to; Asymptotic to - dictionary.put("ne", "\u2260"); // Not equal to - dictionary.put("equiv", "\u2261"); // Identical to - dictionary.put("le", "\u2264"); // Less-than or equal to - dictionary.put("ge", "\u2265"); // Greater-than or equal to - dictionary.put("sub", "\u2282"); // Subset of - dictionary.put("sup", "\u2283"); // Superset of - dictionary.put("nsub", "\u2284"); // Not a subset of - dictionary.put("sube", "\u2286"); // Subset of or equal to - dictionary.put("supe", "\u2287"); // Superset of or equal to - dictionary.put("oplus", "\u2295"); // Circled plus; Direct sum - dictionary.put("otimes", "\u2297"); // Circled times; Vector product - dictionary.put("perp", "\u22A5"); // Up tack; Orthogonal to; Perpendicular - dictionary.put("sdot", "\u22C5"); // Dot operator - - // Arrows - dictionary.put("larr", "\u2190"); // Leftwards arrow - dictionary.put("uarr", "\u2191"); // Upwards arrow - dictionary.put("rarr", "\u2192"); // Rightwards arrow - dictionary.put("darr", "\u2193"); // Downwards arrow - dictionary.put("harr", "\u2194"); // Left right arrow - dictionary.put("crarr", "\u21B5"); // Downwards arrow with corner leftwards; Carriage return symbol - dictionary.put("lArr", "\u21D0"); // Leftwards double arrow - dictionary.put("uArr", "\u21D1"); // Upwards double arrow - dictionary.put("rArr", "\u21D2"); // Rightwards double arrow - dictionary.put("dArr", "\u21D3"); // Downwards double arrow - dictionary.put("hArr", "\u21D4"); // Left right double arrow - - // Greek Capital Letters - dictionary.put("Alpha", "\u0391"); // Greek capital letter alpha - dictionary.put("Beta", "\u0392"); // Greek capital letter beta - dictionary.put("Gamma", "\u0393"); // Greek capital letter gamma - dictionary.put("Delta", "\u0394"); // Greek capital letter delta - dictionary.put("Epsilon", "\u0395"); // Greek capital letter epsilon - dictionary.put("Zeta", "\u0396"); // Greek capital letter zeta - dictionary.put("Eta", "\u0397"); // Greek capital letter eta - dictionary.put("Theta", "\u0398"); // Greek capital letter theta - dictionary.put("Iota", "\u0399"); // Greek capital letter iota - dictionary.put("Kappa", "\u039A"); // Greek capital letter kappa - dictionary.put("Lambda", "\u039B"); // Greek capital letter lambda - dictionary.put("Mu", "\u039C"); // Greek capital letter mu - dictionary.put("Nu", "\u039D"); // Greek capital letter nu - dictionary.put("Xi", "\u039E"); // Greek capital letter xi - dictionary.put("Omicron", "\u039F"); // Greek capital letter omicron - dictionary.put("Pi", "\u03A0"); // Greek capital letter pi - dictionary.put("Rho", "\u03A1"); // Greek capital letter rho - dictionary.put("Sigma", "\u03A3"); // Greek capital letter sigma - dictionary.put("Tau", "\u03A4"); // Greek capital letter tau - dictionary.put("Upsilon", "\u03A5"); // Greek capital letter upsilon - dictionary.put("Phi", "\u03A6"); // Greek capital letter phi - dictionary.put("Chi", "\u03A7"); // Greek capital letter chi - dictionary.put("Psi", "\u03A8"); // Greek capital letter psi - dictionary.put("Omega", "\u03A9"); // Greek capital letter omega - - // Greek Small Letters - dictionary.put("alpha", "\u03B1"); // Greek small letter alpha - dictionary.put("beta", "\u03B2"); // Greek small letter beta - dictionary.put("gamma", "\u03B3"); // Greek small letter gamma - dictionary.put("delta", "\u03B4"); // Greek small letter delta - dictionary.put("epsilon", "\u03B5"); // Greek small letter epsilon - dictionary.put("zeta", "\u03B6"); // Greek small letter zeta - dictionary.put("eta", "\u03B7"); // Greek small letter eta - dictionary.put("theta", "\u03B8"); // Greek small letter theta - dictionary.put("iota", "\u03B9"); // Greek small letter iota - dictionary.put("kappa", "\u03BA"); // Greek small letter kappa - dictionary.put("lambda", "\u03BB"); // Greek small letter lambda - dictionary.put("mu", "\u03BC"); // Greek small letter mu - dictionary.put("nu", "\u03BD"); // Greek small letter nu - dictionary.put("xi", "\u03BE"); // Greek small letter xi - dictionary.put("omicron", "\u03BF"); // Greek small letter omicron - dictionary.put("pi", "\u03C0"); // Greek small letter pi - dictionary.put("rho", "\u03C1"); // Greek small letter rho - dictionary.put("sigmaf", "\u03C2"); // Greek small letter final sigma - dictionary.put("sigma", "\u03C3"); // Greek small letter sigma - dictionary.put("tau", "\u03C4"); // Greek small letter tau - dictionary.put("upsilon", "\u03C5"); // Greek small letter upsilon - dictionary.put("phi", "\u03C6"); // Greek small letter phi - dictionary.put("chi", "\u03C7"); // Greek small letter chi - dictionary.put("psi", "\u03C8"); // Greek small letter psi - dictionary.put("omega", "\u03C9"); // Greek small letter omega - dictionary.put("theta", "\u03D1"); // Greek small letter theta symbol - dictionary.put("upsih", "\u03D2"); // Greek upsilon with hook symbol - dictionary.put("piv", "\u03D6"); // Greek pi symbol - - // Latin Extended-A and Letterlike Symbols - dictionary.put("OElig", "\u0152"); // Latin capital ligature oe - dictionary.put("oelig", "\u0153"); // Latin small ligature oe - dictionary.put("Scaron", "\u0160"); // Latin capital letter s with caron - dictionary.put("scaron", "\u0161"); // Latin small letter s with caron - dictionary.put("Yuml", "\u0178"); // Latin capital letter y with diaeresis - dictionary.put("fnof", "\u0192"); // Latin small f with hook - dictionary.put("weierp", "\u2118"); // Script capital P; Power set; Weierstrass p - dictionary.put("image", "\u2111"); // Blackletter capital I; Imaginary part - dictionary.put("real", "\u211C"); // Blackletter capital R; Real part symbol - dictionary.put("trade", "\u2122"); // Trade mark sign - dictionary.put("alefsym", "\u2135"); // Alef symbol; First transfinite cardinal - - // Miscellaneous Shapes - dictionary.put("spades", "\u2660"); // Black spade suit - dictionary.put("clubs", "\u2663"); // Black club suit; Shamrock - dictionary.put("hearts", "\u2665"); // Black heart suit; Valentine - dictionary.put("diams", "\u2666"); // Black diamond suit - dictionary.put("loz", "\u25CA"); // Lozenge - - // Miscellaneous Technical Symbols - dictionary.put("lceil", "\u2308"); // Left ceiling; Apl upstile - dictionary.put("rceil", "\u2309"); // Right ceiling - dictionary.put("lfloor", "\u230A"); // Left floor; Apl downstile - dictionary.put("rfloor", "\u230B"); // Right floor - dictionary.put("lang", "\u2329"); // Left-pointing angle bracket - dictionary.put("rang", "\u232A"); // Right-pointing angle bracket - - // Spacing Modifier Characters and Bi-directional Characters - dictionary.put("circ", "\u02C6"); // Modifier letter circumflex accent - dictionary.put("tilde", "\u02DC"); // Small tilde - dictionary.put("zwnj", "\u200C"); // Zero width non-joiner - dictionary.put("zwj", "\u200D"); // Zero width joiner - dictionary.put("lrm", "\u200E"); // Left-to-right mark - dictionary.put("rlm", "\u200F"); // Right-to-left mark - - // General Punctuation Set 1 - dictionary.put("bull", "\u2022"); // Bullet; Black small circle - dictionary.put("hellip", "\u2026"); // Horizontal ellipsis; Three dot leader - dictionary.put("prime", "\u2032"); // Prime; Minutes; Feet - dictionary.put("Prime", "\u2033"); // Double prime; Seconds; Inches - dictionary.put("oline", "\u203E"); // Overline; Spacing overscore - dictionary.put("frasl", "\u2044"); // Fraction slash - - // General Punctuation Set 2 - dictionary.put("ensp", "\u2002"); // En space - dictionary.put("emsp", "\u2003"); // Em space - dictionary.put("thinsp", "\u2009"); // Thin space - dictionary.put("zwnj", "\u200C"); // Zero width non-joiner - dictionary.put("zwj", "\u200D"); // Zero width joiner - dictionary.put("lrm", "\u200E"); // Left-to-right mark - dictionary.put("rlm", "\u200F"); // Right-to-left mark - dictionary.put("ndash", "\u2013"); // En dash - dictionary.put("mdash", "\u2014"); // Em dash - dictionary.put("lsquo", "\u2018"); // Left single quotation mark - dictionary.put("rsquo", "\u2019"); // Right single quotation mark - dictionary.put("sbquo", "\u201A"); // Single low-9 quotation mark - dictionary.put("ldquo", "\u201C"); // Left double quotation mark - dictionary.put("rdquo", "\u201D"); // Right double quotation mark - dictionary.put("bdquo", "\u201E"); // Double low-9 quotation mark - dictionary.put("dagger", "\u2020"); // Dagger - dictionary.put("Dagger", "\u2021"); // Double dagger - dictionary.put("permil", "\u2030"); // Per mille sign - dictionary.put("lsaquo", "\u2039"); // Single left-pointing angle quotation mark - dictionary.put("rsaquo", "\u203A"); // Single right-pointing angle quotation mark - dictionary.put("euro", "\u20AC"); // Euro - - return dictionary; - } - - /** - * Converts the characters that are reserved in an XML document the given string may have into - * their corresponding references (escape characters) using the character entity reference. - * - * @param value A string that may contain characters that need to be escaped - * @param positions This array of length one or two can be used to adjust the position of the - * cursor or a text range within the string during the conversion of the reserved characters - * @return The given string with any reserved characters converted into the escape characters - */ - public static String escape(String value, int[] positions) { - - if ((value == null) || (value.length() == 0)) { - return value; - } - - StringBuilder sb = new StringBuilder(value.length()); - int startPosition = positions[0]; - int endPosition = (positions.length > 1) ? positions[1] : -1; - - for (int index = 0, count = value.length(); index < count; index++) { - - char character = value.charAt(index); - - // The character is one of the reserved character - if (isReserved(character)) { - - // Retrieve the corresponding entity name - String name = getEscapeCharacter(character); - sb.append(name); - - // Adjust the position - if (startPosition > index) { - // -1 for the character itself that is replaced by the entity name - positions[0] += (name.length() - 1); - } - - if ((endPosition > -1) && (index < endPosition)) { - // -1 for the character itself that is replaced by the entity name - positions[1] += (name.length() - 1); - } - } - else { - sb.append(character); - } - } - - return sb.toString(); - } - - /** - * Returns the Unicode character for the given reference (which is either a numeric character - * reference or a character entity reference). - * - * @param reference The numeric character or character entity reference stripped of the leading - * ampersand and trailing semi-colon - * @return The Unicode character mapped to the given reference or <code>null</code> if the - * reference is invalid or unknown - */ - public static String getCharacter(String reference) { - - if (reference == null) { - return null; - } - - int length = reference.length(); - - if (length == 0) { - return null; - } - - // Character reference - if (reference.charAt(0) == '#') { - - if (length == 1) { - return null; - } - - // Parse the numeric value - String value; - int radix; - - // Hexadecimal - if (reference.charAt(1) == 'x') { - radix = 16; - value = reference.substring(2); - } - // Decimal - else { - radix = 10; - value = reference.substring(1); - } - - // No minus accepted - if ((value.length() == 0) || (value.charAt(0) == '-')) { - return null; - } - - // Convert the numeric value into the actual character - char character = 0; - - try { - character = (char) Integer.parseInt(value, radix); - } - catch (NumberFormatException ex) { - // Simply ignore - } - - // The null character � is not permitted - if (character == 0) { - return null; - } - - return String.valueOf(character); - } - - // Entity reference - return dictionary.get(reference); - } - - /** - * Returns the escaped character for the given reserved character. - * - * @param character The reserved character to retrieve its escape character with the entity name - * @return The escape character with the entity name of the given character if it is a reserved - * character; otherwise returns <code>null</code> - */ - public static String getEscapeCharacter(char character) { - - switch (character) { - case '<': return LESS_THAN_ENTITY_NAME; - case '>': return GREATER_THAN_ENTITY_NAME; - case '&': return AMPERSAND_ENTITY_NAME; - case '\'': return APOSTROPHE_ENTITY_NAME; - case '\"': return QUOTATION_MARK_NAME; - default: return null; - } - } - - /** - * Determines if the given character is one of the XML/HTML reserved characters. - * - * @param character The character to verify if it's one of the reserved characters - * @return <code>true</code> if the given character is defined as a reserved characters; - * <code>false</code> otherwise - */ - public static boolean isReserved(char character) { - - switch (character) { - case '<': - case '>': - case '&': - case '\'': - case '\"': return true; - default: return false; - } - } - - /** - * Re-adjusts the given positions, which is based on the non-escaped version of the given - * <em>query</em>, by making sure it is pointing at the same position within <em>query</em>, - * which contains references (escape characters). - * <p> - * The escape characters are either the character entity references or the numeric character - * references used in an XML document. - * <p> - * <b>Important:</b> The given query should contain the exact same amount of whitespace than the - * query used to calculate the given positions. - * - * @param query The query that may contain escape characters - * @param positions The position within the non-escaped version of the given query, which is - * either a single element position or two positions that is used as a text range - * @return The adjusted positions by moving it based on the difference between the escape and - * non-escaped versions of the query - * @since 2.5 - */ - public static void reposition(CharSequence query, int[] positions) { - - if ((query == null) || (query.length() == 0)) { - return; - } - - StringBuilder sb = new StringBuilder(query); - - for (int index = 0, count = sb.length(); index < count; index++) { - - char character = sb.charAt(index); - - // The beginning of the escape character - if ((character == '&') && (index + 1 < count)) { - - // Find the ending of the escape character - int semiColonIndex = sb.indexOf(";", index + 1); - - if (semiColonIndex > -1) { - - // Retrieve the reference value - String reference = sb.substring(index + 1, semiColonIndex); - - if (reference.length() > 0) { - - // Retrieve the character mapped to the entity name - String unicodeCharacter = XmlEscapeCharacterConverter.getCharacter(reference); - - if (unicodeCharacter != null) { - - // length = '&' + 'reference' + ';' - 'Unicode character' - int length = (semiColonIndex - index); - - // Translate both positions because a Unicode - // character is written with its escape character - if (index < positions[0]) { - positions[0] += length; - positions[1] += length; - } - // Only translate the end position because the start - // position is before the current index - else if (index < positions[1]) { - positions[1] += length; - } - - index = semiColonIndex; - } - } - } - } - } - } - - /** - * Converts the references (escape characters) the given string may have into their corresponding - * Unicode characters. - * <p> - * <ul> - * <li>Character entity reference: <b>&copy;</b> for <b>©</b></li> - * <li>Numeric character reference (decimal value): <b>&#169;</b> for <b>©</b></li> - * <li>Numeric character reference (hexadecimal value): <b>&#xA9;</b> for <b>©</b></li> - * </ul> - * </p> - * - * @param value A string that may contain escape characters - * @param position This array of length one can be used to adjust the position of the cursor - * within the string during the conversion of the escape characters - * @return The given string with any escape characters converted into the actual Unicode characters - */ - public static String unescape(String value, int[] position) { - - if ((value == null) || (value.length() == 0)) { - return value; - } - - StringBuilder sb = new StringBuilder(value); - - for (int index = 0, count = sb.length(); index < count; index++) { - - char character = sb.charAt(index); - - // The beginning of the escape character - if ((character == '&') && (index + 1 < count)) { - - // Find the ending of the escape character - int semiColonIndex = sb.indexOf(";", index + 1); - - if (semiColonIndex > -1) { - - // Retrieve the reference - String reference = sb.substring(index + 1, semiColonIndex); - - if (reference.length() > 0) { - - // Retrieve the character mapped to the reference - String specialCharacter = getCharacter(reference); - - if (specialCharacter != null) { - - // Replace the reference by the Unicode character - sb.replace(index, semiColonIndex + 1, specialCharacter); - - // Make sure the count is updated - count -= (semiColonIndex - index); - - // "& + reference + ; - Unicode character" - int length = (1 + reference.length()); - - // Adjust the position - // Case 1: The cursor is within the escape character, move it to the beginning - if ((position[0] >= index) && (position[0] <= index + length)) { - position[0] = index; - } - // Case 2: the cursor is after the escape character, just do an adjustment as - // if it was a single character - else if (position[0] > index + length) { - position[0] -= length; - } - } - } - } - } - } - - return sb.toString(); - } -}
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaEntity.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaEntity.java index 4c29b2ac23..0dc443bac1 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaEntity.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaEntity.java @@ -15,14 +15,12 @@ package org.eclipse.jpt.jpa.core.jpql.spi; import java.util.HashMap; import java.util.Map; - import org.eclipse.jpt.common.utility.iterable.ListIterable; import org.eclipse.jpt.jpa.core.context.AttributeMapping; import org.eclipse.jpt.jpa.core.context.Entity; import org.eclipse.jpt.jpa.core.context.NamedQuery; import org.eclipse.persistence.jpa.jpql.spi.IEntity; import org.eclipse.persistence.jpa.jpql.spi.IManagedTypeVisitor; -import org.eclipse.persistence.jpa.jpql.spi.IMapping; import org.eclipse.persistence.jpa.jpql.spi.IMappingBuilder; import org.eclipse.persistence.jpa.jpql.spi.IQuery; diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaManagedTypeProvider.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaManagedTypeProvider.java index 87ac48d828..c5a97655b6 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaManagedTypeProvider.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaManagedTypeProvider.java @@ -31,7 +31,6 @@ import org.eclipse.persistence.jpa.jpql.spi.IEntity; import org.eclipse.persistence.jpa.jpql.spi.IManagedType; import org.eclipse.persistence.jpa.jpql.spi.IManagedTypeProvider; import org.eclipse.persistence.jpa.jpql.spi.IMappedSuperclass; -import org.eclipse.persistence.jpa.jpql.spi.IMapping; import org.eclipse.persistence.jpa.jpql.spi.IMappingBuilder; import org.eclipse.persistence.jpa.jpql.spi.IType; diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/GenericJpaJpqlHyperlinkBuilder.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/GenericJpaJpqlHyperlinkBuilder.java index 0e9c6d2497..c818f1309a 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/GenericJpaJpqlHyperlinkBuilder.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/GenericJpaJpqlHyperlinkBuilder.java @@ -19,25 +19,20 @@ import org.eclipse.jpt.common.utility.internal.StringTools; import org.eclipse.jpt.jpa.core.context.Entity; import org.eclipse.jpt.jpa.core.context.NamedQuery; import org.eclipse.jpt.jpa.core.jpql.JpaJpqlQueryHelper; +import org.eclipse.persistence.jpa.jpql.BaseDeclarationIdentificationVariableFinder; import org.eclipse.persistence.jpa.jpql.Resolver; import org.eclipse.persistence.jpa.jpql.StateFieldResolver; import org.eclipse.persistence.jpa.jpql.parser.AbstractPathExpression; import org.eclipse.persistence.jpa.jpql.parser.AbstractSchemaName; import org.eclipse.persistence.jpa.jpql.parser.AbstractTraverseParentVisitor; -import org.eclipse.persistence.jpa.jpql.parser.CollectionExpression; import org.eclipse.persistence.jpa.jpql.parser.CollectionValuedPathExpression; import org.eclipse.persistence.jpa.jpql.parser.ConstructorExpression; -import org.eclipse.persistence.jpa.jpql.parser.DeleteClause; -import org.eclipse.persistence.jpa.jpql.parser.DeleteStatement; import org.eclipse.persistence.jpa.jpql.parser.EntityTypeLiteral; import org.eclipse.persistence.jpa.jpql.parser.Expression; import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable; -import org.eclipse.persistence.jpa.jpql.parser.NullExpression; import org.eclipse.persistence.jpa.jpql.parser.QueryPosition; import org.eclipse.persistence.jpa.jpql.parser.RangeVariableDeclaration; import org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression; -import org.eclipse.persistence.jpa.jpql.parser.UpdateClause; -import org.eclipse.persistence.jpa.jpql.parser.UpdateStatement; import org.eclipse.persistence.jpa.jpql.spi.IMapping; import org.eclipse.persistence.jpa.jpql.spi.IType; @@ -79,7 +74,7 @@ public class GenericJpaJpqlHyperlinkBuilder extends JpaJpqlHyperlinkBuilder { } protected final IdentificationVariable findVirtualIdentificationVariable(AbstractSchemaName expression) { - VirtualIdentificationVariableFinder visitor = new VirtualIdentificationVariableFinder(); + BaseDeclarationIdentificationVariableFinder visitor = new BaseDeclarationIdentificationVariableFinder(); expression.accept(visitor); return visitor.expression; } @@ -422,112 +417,4 @@ public class GenericJpaJpqlHyperlinkBuilder extends JpaJpqlHyperlinkBuilder { rangeVariableDeclaration = true; } } - - /** - * This visitor traverses the parsed tree and retrieves the {@link IdentificationVariable} - * defined for a range variable declaration. - * <p> - * TODO: REMOVE AND USE BaseDeclarationIdentificationVariableFinder ONE AVAILABLE IN ECLIPSELINK HERMES. - */ - protected static class VirtualIdentificationVariableFinder extends AbstractTraverseParentVisitor { - - /** - * The {@link IdentificationVariable} used to define the abstract schema name from either the - * <b>UPDATE</b> or <b>DELETE</b> clause. - */ - protected IdentificationVariable expression; - - /** - * Determines if the {@link RangeVariableDeclaration} should traverse its identification - * variable expression or simply visit the parent hierarchy. - */ - protected boolean traverse; - - /** - * {@inheritDoc} - */ - @Override - public void visit(CollectionExpression expression) { - if (traverse) { - // Invalid query, scan the first expression only - expression.getChild(0).accept(this); - } - else { - super.visit(expression); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void visit(DeleteClause expression) { - try { - traverse = true; - expression.getRangeVariableDeclaration().accept(this); - } - finally { - traverse = false; - } - } - - /** - * {@inheritDoc} - */ - @Override - public void visit(DeleteStatement expression) { - expression.getDeleteClause().accept(this); - } - - /** - * {@inheritDoc} - */ - @Override - public void visit(IdentificationVariable expression) { - this.expression = expression; - } - - /** - * {@inheritDoc} - */ - @Override - public void visit(NullExpression expression) { - // Incomplete/invalid query, stop here - } - - /** - * {@inheritDoc} - */ - @Override - public void visit(RangeVariableDeclaration expression) { - if (traverse) { - expression.getIdentificationVariable().accept(this); - } - else { - super.visit(expression); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void visit(UpdateClause expression) { - try { - traverse = true; - expression.getRangeVariableDeclaration().accept(this); - } - finally { - traverse = false; - } - } - - /** - * {@inheritDoc} - */ - @Override - public void visit(UpdateStatement expression) { - expression.getUpdateClause().accept(this); - } - } }
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlJavaCompletionProposalComputer.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlJavaCompletionProposalComputer.java index c68a764758..731ee3449d 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlJavaCompletionProposalComputer.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlJavaCompletionProposalComputer.java @@ -92,7 +92,7 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP namedQuery, jpqlQuery, tokenStart + 1, // +1 is to skip the opening " - tokenEnd - 1, // -1 is to skip the closing " + tokenEnd, // Don't do -1 to skip the closing ", the length is right since it's tokenEnd - tokenStart position, cursorOffset ); @@ -345,7 +345,7 @@ public final class JpaJpqlJavaCompletionProposalComputer extends JpqlCompletionP // because content assist will only replace one string literal and right now we // only support replacing the entire string tokenStart[0] = child.getStartPosition(); - tokenEnd[0] = child.getStartPosition() + child.getLength(); + tokenEnd[0] = child.getStartPosition() + child.getLength() - 1; return sb.toString(); } diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlSseCompletionProposalComputer.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlSseCompletionProposalComputer.java index 35bf3554f5..f248ca0c78 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlSseCompletionProposalComputer.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpaJpqlSseCompletionProposalComputer.java @@ -37,9 +37,9 @@ import org.eclipse.jpt.jpa.core.context.orm.EntityMappings; import org.eclipse.jpt.jpa.core.context.orm.OrmEntity; import org.eclipse.jpt.jpa.core.context.orm.OrmNamedQuery; import org.eclipse.jpt.jpa.core.context.orm.OrmQueryContainer; -import org.eclipse.jpt.jpa.core.jpql.XmlEscapeCharacterConverter; import org.eclipse.jpt.jpa.ui.internal.JptUiMessages; import org.eclipse.jpt.jpa.ui.internal.plugin.JptJpaUiPlugin; +import org.eclipse.persistence.jpa.jpql.util.XmlEscapeCharacterConverter; import org.eclipse.swt.graphics.Image; import org.eclipse.wst.sse.ui.contentassist.CompletionProposalInvocationContext; import org.eclipse.wst.sse.ui.contentassist.ICompletionProposalComputer; @@ -226,7 +226,6 @@ public final class JpaJpqlSseCompletionProposalComputer extends JpqlCompletionPr // The JPQL query is not encapsulated by a CDATA section, // converts any escape characters like < into '<' if (!cDATASection) { - // TODO: UPDATE TO USE ECLIPSELINK HERMES 2.5 M2 ONCE IT IS AVAILABLE jpqlQuery = XmlEscapeCharacterConverter.unescape(jpqlQuery, position); } diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposal.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposal.java index cf9b6f53f1..9cfe4009f5 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposal.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposal.java @@ -147,4 +147,12 @@ abstract class JpqlCompletionProposal implements ICompletionProposal { String value = PreferenceConstants.getPreference(PreferenceConstants.CODEASSIST_INSERT_COMPLETION, javaProject); return Boolean.valueOf(value); } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return proposal; + } }
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposalComputer.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposalComputer.java index 5a4c5b6750..94d8b8b6b5 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposalComputer.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlCompletionProposalComputer.java @@ -13,16 +13,6 @@ ******************************************************************************/ package org.eclipse.jpt.jpa.ui.internal.jpql; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.BASIC; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.ELEMENT_COLLECTION; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.EMBEDDED; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.EMBEDDED_ID; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.ID; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.MANY_TO_MANY; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.MANY_TO_ONE; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.ONE_TO_MANY; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.ONE_TO_ONE; -import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.VERSION; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -30,22 +20,27 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jpt.common.core.internal.utility.PlatformTools; +import org.eclipse.jpt.common.utility.internal.CharacterTools; +import org.eclipse.jpt.common.utility.internal.StringTools; import org.eclipse.jpt.common.utility.internal.iterable.IterableTools; import org.eclipse.jpt.jpa.core.JpaPreferences; import org.eclipse.jpt.jpa.core.context.NamedQuery; import org.eclipse.jpt.jpa.core.jpql.JpaJpqlQueryHelper; import org.eclipse.jpt.jpa.ui.JpaWorkbench; import org.eclipse.jpt.jpa.ui.JptJpaUiImages; -import org.eclipse.jpt.jpa.ui.internal.plugin.JptJpaUiPlugin; import org.eclipse.persistence.jpa.jpql.ContentAssistProposals; +import org.eclipse.persistence.jpa.jpql.ContentAssistProposals.ClassType; +import org.eclipse.persistence.jpa.jpql.ContentAssistProposals.EnumProposals; import org.eclipse.persistence.jpa.jpql.WordParser; import org.eclipse.persistence.jpa.jpql.parser.Expression; import org.eclipse.persistence.jpa.jpql.parser.IdentifierRole; import org.eclipse.persistence.jpa.jpql.spi.IEntity; import org.eclipse.persistence.jpa.jpql.spi.IMapping; +import org.eclipse.persistence.jpa.jpql.spi.IType; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.PlatformUI; +import static org.eclipse.persistence.jpa.jpql.spi.IMappingType.*; /** * The abstract definition of JPQL content assist support. @@ -111,37 +106,45 @@ abstract class JpqlCompletionProposalComputer<T> { /** * Creates a new <code>JpqlCompletionProposalComputer</code>. */ - JpqlCompletionProposalComputer() { + public JpqlCompletionProposalComputer() { super(); } - /** - * Adds completion proposals for the abstract schema names that are possible proposals. - * - * @param proposals The list used to store the new completion proposals - */ - private void addAbstractSchemaNames(List<T> proposals, ResourceManager resourceManager) { - for (IEntity abstractSchemaType : sortByNames(contentAssistProposals.abstractSchemaTypes())) { - proposals.add(buildAbstractSchemaNameProposal(abstractSchemaType, resourceManager)); + private void addClassNames(List<T> proposals, ResourceManager resourceManager) { + + ClassType classType = contentAssistProposals.getClassType(); + + for (String className : sort(contentAssistProposals.classNames())) { + proposals.add(buildClassNameProposal(className, classType, resourceManager)); + } + } + + private void addColumnNames(List<T> proposals, ResourceManager resourceManager) { + for (String columnName : sort(contentAssistProposals.columnNames())) { + proposals.add(buildColumnNameProposal(columnName, resourceManager)); + } + } + + private void addEntityNames(List<T> proposals, ResourceManager resourceManager) { + for (IEntity entity : sortByNames(contentAssistProposals.abstractSchemaTypes())) { + proposals.add(buildEntityNameProposal(entity, resourceManager)); + } + } + + private void addEnumConstantNames(List<T> proposals, ResourceManager resourceManager) { + for (EnumProposals enumProposal : contentAssistProposals.enumConstant()) { + IType enumType = enumProposal.enumType(); + for (String enumConstant : sort(enumProposal.enumConstants())) + proposals.add(buildEnumConstantNameProposal(enumType, enumConstant, resourceManager)); } } - /** - * Adds completion proposals for the identification variables that are possible proposals. - * - * @param proposals The list used to store the new completion proposals - */ private void addIdentificationVariables(List<T> proposals, ResourceManager resourceManager) { for (String variable : sort(contentAssistProposals.identificationVariables())) { proposals.add(buildIdentificationVariableProposal(variable, resourceManager)); } } - /** - * Adds completion proposals for the JPQL identifiers that are possible proposals. - * - * @param proposals The list used to store the new completion proposals - */ private void addIdentifiers(List<T> proposals, ResourceManager resourceManager) { for (String identifier : sort(contentAssistProposals.identifiers())) { proposals.add(buildIdentifierProposal(identifier, resourceManager)); @@ -152,20 +155,49 @@ abstract class JpqlCompletionProposalComputer<T> { return JpqlIdentifierMessages.localizedMessage(proposal); } - /** - * Adds completion proposals for the state fields and association fields that are possible proposals. - * - * @param proposals The list used to store the new completion proposals - */ private void addMappings(List<T> proposals, ResourceManager resourceManager) { for (IMapping mapping : sort(contentAssistProposals.mappings())) { proposals.add(buildMappingProposal(mapping, resourceManager)); } } - private T buildAbstractSchemaNameProposal(IEntity abstractSchemaType, ResourceManager resourceManager) { - String proposal = abstractSchemaType.getName(); - return buildProposal(proposal, proposal, resourceManager.createImage(JptJpaUiImages.ENTITY)); + private void addTableNames(List<T> proposals, ResourceManager resourceManager) { + for (String tableName : sort(contentAssistProposals.tableNames())) { + proposals.add(buildTableNameProposal(tableName, resourceManager)); + } + } + + private T buildClassNameProposal(String className, ClassType type, ResourceManager resourceManager) { + + String displayString = className; + int dotIndex = className.lastIndexOf('.'); + + if (dotIndex > -1) { + StringBuilder sb = new StringBuilder(); + sb.append(className.substring(dotIndex + 1)); + sb.append(" - "); + sb.append(className.substring(0, dotIndex)); + displayString = sb.toString(); + } + + Image image; + + if (type == ClassType.INSTANTIABLE) { + image = resourceManager.createImage(JptJpaUiImages.CLASS_REF); + } + else { + image = resourceManager.createImage(JptJpaUiImages.ENUM); + } + + return buildProposal(className, displayString, image); + } + + private T buildColumnNameProposal(String columnName, ResourceManager resourceManager) { + return buildProposal( + columnName, + columnName, + resourceManager.createImage(JptJpaUiImages.COLUMN) + ); } private Comparator<IEntity> buildEntityNameComparator() { @@ -176,15 +208,36 @@ abstract class JpqlCompletionProposalComputer<T> { }; } + private T buildEntityNameProposal(IEntity entity, ResourceManager resourceManager) { + String proposal = entity.getName(); + return buildProposal(proposal, proposal, resourceManager.createImage(JptJpaUiImages.ENTITY)); + } + + private T buildEnumConstantNameProposal(IType enumType, + String enumConstant, + ResourceManager resourceManager) { + + StringBuilder sb = new StringBuilder(); + sb.append(enumConstant); + sb.append(" : "); + sb.append(enumType.getName()); + + return buildProposal( + enumConstant, + sb.toString(), + resourceManager.createImage(JptJpaUiImages.ENUM) + ); + } + private String buildIdentificationVariableDisplayString(String identificationVariable) { - IEntity abstractSchemaType = contentAssistProposals.getAbstractSchemaType(identificationVariable); + IEntity entity = contentAssistProposals.getAbstractSchemaType(identificationVariable); - if (abstractSchemaType != null) { + if (entity != null) { StringBuilder sb = new StringBuilder(); sb.append(identificationVariable); sb.append(" : "); - sb.append(abstractSchemaType.getName()); + sb.append(entity.getName()); identificationVariable = sb.toString(); } @@ -226,6 +279,7 @@ abstract class JpqlCompletionProposalComputer<T> { } Image image = resourceManager.createImage(realFunction ? JptJpaUiImages.JPQL_FUNCTION : JptJpaUiImages.JPQL_IDENTIFIER); + return buildProposal( proposal, proposal, @@ -271,9 +325,11 @@ abstract class JpqlCompletionProposalComputer<T> { * @param namedQuery The model object used to access the application metadata information * @param actualQuery The string representation of the JPQL query that is coming from the * document itself (Java source or XML) - * @param offset The beginning of the string within the document - * @param position The position of the cursor within the query, which starts at the beginning of + * @param tokenStart The beginning of the string within the document + * @param tokenEnd The position of the cursor within the query, which starts at the beginning of * that query and not the document + * @param position + * @param resourceManager The manager of resources, such as images * @return The list of completion proposals */ final List<T> buildProposals(NamedQuery namedQuery, @@ -307,10 +363,14 @@ abstract class JpqlCompletionProposalComputer<T> { // Create the proposals for those proposals List<T> proposals = new ArrayList<T>(); - addAbstractSchemaNames (proposals, resourceManager); + addMappings (proposals, resourceManager); addIdentificationVariables(proposals, resourceManager); + addEntityNames (proposals, resourceManager); + addTableNames (proposals, resourceManager); + addColumnNames (proposals, resourceManager); + addClassNames (proposals, resourceManager); + addEnumConstantNames (proposals, resourceManager); addIdentifiers (proposals, resourceManager); - addMappings (proposals, resourceManager); return proposals; } @@ -322,6 +382,11 @@ abstract class JpqlCompletionProposalComputer<T> { } } + private T buildTableNameProposal(String tableName, ResourceManager resourceManager) { + String proposal = StringTools.delimit(tableName, CharacterTools.SINGLE_QUOTE); + return buildProposal(proposal, proposal, resourceManager.createImage(JptJpaUiImages.TABLE)); + } + final void checkCanceled(IProgressMonitor monitor) throws InterruptedException { if (monitor.isCanceled()) { throw new InterruptedException(); @@ -352,14 +417,14 @@ abstract class JpqlCompletionProposalComputer<T> { return null; } - ResourceManager getResourceManager(Control control) { - return this.getJpaWorkbench().getResourceManager(control); - } - JpaWorkbench getJpaWorkbench() { return PlatformTools.getAdapter(PlatformUI.getWorkbench(), JpaWorkbench.class); } + ResourceManager getResourceManager(Control control) { + return this.getJpaWorkbench().getResourceManager(control); + } + private boolean isRealFunction(String identifier) { return identifier != Expression.TRUE && identifier != Expression.FALSE && @@ -438,4 +503,4 @@ abstract class JpqlCompletionProposalComputer<T> { private Iterable<IEntity> sortByNames(Iterable<IEntity> abstractSchemaTypes) { return IterableTools.sort(abstractSchemaTypes, buildEntityNameComparator()); } -} +}
\ No newline at end of file diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlSseCompletionProposal.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlSseCompletionProposal.java index 992af926d7..a6d3af262c 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlSseCompletionProposal.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/jpql/JpqlSseCompletionProposal.java @@ -13,15 +13,9 @@ ******************************************************************************/ package org.eclipse.jpt.jpa.ui.internal.jpql; -import java.lang.reflect.Method; -import org.eclipse.jpt.common.utility.internal.StringTools; import org.eclipse.jpt.jpa.core.context.NamedQuery; -import org.eclipse.jpt.jpa.core.jpql.XmlEscapeCharacterConverter; import org.eclipse.persistence.jpa.jpql.ContentAssistProposals; -import org.eclipse.persistence.jpa.jpql.DefaultContentAssistProposals; -import org.eclipse.persistence.jpa.jpql.ExpressionTools; import org.eclipse.persistence.jpa.jpql.ResultQuery; -import org.eclipse.persistence.jpa.jpql.WordParser; import org.eclipse.swt.graphics.Image; /** @@ -83,58 +77,11 @@ final class JpqlSseCompletionProposal extends JpqlCompletionProposal { ); } - // TODO: UPDATE ONCE THE NEXT ECLIPSELINK HERMES 2.5 MILESTONE IS AVAILABLE - return /*proposals.*/buildXmlQuery( + return proposals.buildXmlQuery( actualJpqlQuery, proposal, actualPosition, isCompletionInserts() ^ toggleCompletion ); } - - /** - * TODO: TO DELETE ONCE USING THE NEXT ECLIPSELINK HERMES 2.5 MILESTONE - */ - @SuppressWarnings("nls") - private ResultQuery buildXmlQuery(String jpqlQuery, String proposal, int position, boolean insert) { - - // Nothing to replace - if (ExpressionTools.stringIsEmpty(proposal)) { - return proposals.buildQuery(jpqlQuery, StringTools.EMPTY_STRING, position, false); - } - - int[] positions = { position }; - - // First convert the escape characters into their unicode characters - String query = XmlEscapeCharacterConverter.unescape(jpqlQuery, positions); - - // Calculate the start and end positions - WordParser wordParser = new WordParser(query); - wordParser.setPosition(positions[0]); - - // int[] proposalPositions = buildPositions(wordParser, proposal, insert); - int[] proposalPositions; - try { - Method buildPositionsMethod = DefaultContentAssistProposals.class.getDeclaredMethod("buildPositions", WordParser.class, String.class, boolean.class); - buildPositionsMethod.setAccessible(true); - proposalPositions = (int[]) buildPositionsMethod.invoke(proposals, wordParser, proposal, insert); - } - catch (Exception e) { - // This is temporary - proposalPositions = new int[2]; - } - - // Escape the proposal - proposal = XmlEscapeCharacterConverter.escape(proposal, new int[1]); - - // Adjust the positions so it's in the original JPQL query, which may contain escaped characters - XmlEscapeCharacterConverter.reposition(jpqlQuery, proposalPositions); - - // Create the new JPQL query - StringBuilder sb = new StringBuilder(jpqlQuery); - sb.replace(proposalPositions[0], proposalPositions[1], proposal); - - // And simply create a new ResultQuery object - return proposals.buildQuery(sb.toString(), StringTools.EMPTY_STRING, proposalPositions[0] + proposal.length(), false); - } }
\ No newline at end of file |