| /******************************************************************************* |
| * Copyright (c) 2007, 2012 Oracle. 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: |
| * Oracle - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.jpt.jpa.core.internal.jpa1.context.orm; |
| |
| import java.util.List; |
| import org.eclipse.jpt.common.core.utility.TextRange; |
| import org.eclipse.jpt.jpa.core.context.ReadOnlyNamedColumn; |
| import org.eclipse.jpt.jpa.core.context.orm.OrmAttributeMapping; |
| import org.eclipse.jpt.jpa.core.context.orm.OrmPersistentAttribute; |
| import org.eclipse.jpt.jpa.core.internal.context.JptValidator; |
| import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; |
| import org.eclipse.jpt.jpa.core.internal.context.orm.AbstractOrmXmlContextNode; |
| import org.eclipse.jpt.jpa.core.internal.jpa2.context.OrderColumnValidator; |
| import org.eclipse.jpt.jpa.core.jpa2.context.OrderColumn2_0; |
| import org.eclipse.jpt.jpa.core.jpa2.context.orm.OrmOrderColumn2_0; |
| import org.eclipse.jpt.jpa.core.jpa2.context.orm.OrmOrderable2_0; |
| import org.eclipse.jpt.jpa.core.resource.orm.OrmFactory; |
| import org.eclipse.jpt.jpa.core.resource.orm.XmlOrderColumn; |
| import org.eclipse.jpt.jpa.core.resource.orm.XmlOrderable; |
| import org.eclipse.jpt.jpa.db.Table; |
| import org.eclipse.wst.validation.internal.provisional.core.IMessage; |
| import org.eclipse.wst.validation.internal.provisional.core.IReporter; |
| |
| /** |
| * <code>orm.xml</code> ordering |
| * <p> |
| * <strong>NB:</strong> Setting any flag to <code>false</code> (or setting the |
| * specified "order by" to <code>null</code>) can be a bit unpredictable. The |
| * intent is to set a flag to <code>true</code> (or set the specified "order by" |
| * to a non-<code>null</code> value). |
| * <p> |
| * <strong>(JPA 2.0 only) NB:</strong> If both the "order-by" and the |
| * "order-column" elements are present (which is prohibited by the JPA spec), |
| * both are ignored. |
| */ |
| public class GenericOrmOrderable |
| extends AbstractOrmXmlContextNode |
| implements OrmOrderable2_0 |
| { |
| protected String specifiedOrderBy; |
| protected boolean noOrdering = false; |
| protected boolean pkOrdering = false; |
| protected boolean customOrdering = false; |
| |
| // JPA 2.0 |
| protected final Owner owner; // this is null for JPA 1.0 mappings |
| protected boolean orderColumnOrdering = false; |
| protected final OrmOrderColumn2_0 orderColumn; // this is null for JPA 1.0 mappings |
| |
| |
| /** |
| * JPA 1.0 |
| */ |
| public GenericOrmOrderable(OrmAttributeMapping parent) { |
| this(parent, null); |
| } |
| |
| /** |
| * JPA 2.0 |
| */ |
| public GenericOrmOrderable(OrmAttributeMapping parent, Owner owner) { |
| super(parent); |
| |
| this.specifiedOrderBy = this.buildSpecifiedOrderBy(); |
| this.noOrdering = this.buildNoOrdering(); |
| this.pkOrdering = this.buildPkOrdering(); |
| this.customOrdering = this.buildCustomOrdering(); |
| |
| this.owner = owner; |
| this.orderColumnOrdering = this.buildOrderColumnOrdering(); |
| this.orderColumn = this.buildOrderColumn(); |
| } |
| |
| |
| // ********** synchronize/update ********** |
| |
| @Override |
| public void synchronizeWithResourceModel() { |
| super.synchronizeWithResourceModel(); |
| |
| this.setSpecifiedOrderBy_(this.buildSpecifiedOrderBy()); |
| this.setNoOrdering_(this.buildNoOrdering()); |
| this.setPkOrdering_(this.buildPkOrdering()); |
| this.setCustomOrdering_(this.buildCustomOrdering()); |
| |
| this.setOrderColumnOrdering_(this.buildOrderColumnOrdering()); |
| if (this.orderColumn != null) { |
| this.orderColumn.synchronizeWithResourceModel(); |
| } |
| } |
| |
| @Override |
| public void update() { |
| super.update(); |
| if (this.orderColumn != null) { |
| this.orderColumn.update(); |
| } |
| } |
| |
| |
| // ********** specified order by ********** |
| |
| public String getSpecifiedOrderBy() { |
| return this.specifiedOrderBy; |
| } |
| |
| public void setSpecifiedOrderBy(String orderBy) { |
| if (orderBy != null) { |
| this.setSpecifiedOrderBy_(orderBy); |
| this.setNoOrdering_(false); |
| this.setPkOrdering_(orderBy.length() == 0); |
| this.setCustomOrdering_(orderBy.length() != 0); |
| this.setOrderColumnOrdering_(false); |
| |
| this.removeXmlOrderColumn(); |
| this.getXmlOrderable().setOrderBy(orderBy); |
| } else { |
| this.setNoOrdering(true); // hmmm... |
| } |
| } |
| |
| protected void setSpecifiedOrderBy_(String orderBy) { |
| String old = this.specifiedOrderBy; |
| this.specifiedOrderBy = orderBy; |
| this.firePropertyChanged(SPECIFIED_ORDER_BY_PROPERTY, old, orderBy); |
| } |
| |
| protected String buildSpecifiedOrderBy() { |
| if (this.xmlOrderColumnIsPresent()) { |
| return null; |
| } |
| return this.getXmlOrderBy(); |
| } |
| |
| |
| // ********** no ordering ********** |
| |
| public boolean isNoOrdering() { |
| return this.noOrdering; |
| } |
| |
| public void setNoOrdering(boolean noOrdering) { |
| if (noOrdering) { |
| this.setSpecifiedOrderBy_(null); |
| this.setNoOrdering_(true); |
| this.setPkOrdering_(false); |
| this.setCustomOrdering_(false); |
| this.setOrderColumnOrdering_(false); |
| |
| this.removeXmlOrderColumn(); |
| this.getXmlOrderable().setOrderBy(null); |
| } else { |
| this.setPkOrdering(true); // hmmm... |
| } |
| } |
| |
| protected void setNoOrdering_(boolean noOrdering) { |
| boolean old = this.noOrdering; |
| this.noOrdering = noOrdering; |
| this.firePropertyChanged(NO_ORDERING_PROPERTY, old, noOrdering); |
| } |
| |
| protected boolean buildNoOrdering() { |
| return this.isJpa2_0Compatible() ? this.buildNoOrdering2_0() : this.buildNoOrdering1_0(); |
| } |
| |
| /** |
| * both elements are missing <em>or</em> both are present |
| */ |
| protected boolean buildNoOrdering2_0() { |
| boolean orderByMissing = (this.getXmlOrderBy() == null); |
| boolean orderByPresent = ! orderByMissing; |
| boolean orderColumnMissing = (this.getXmlOrderColumn() == null); |
| boolean orderColumnPresent = ! orderColumnMissing; |
| return (orderByMissing && orderColumnMissing) || (orderByPresent && orderColumnPresent); |
| } |
| |
| /** |
| * the order-by element is missing |
| */ |
| protected boolean buildNoOrdering1_0() { |
| return this.getXmlOrderBy() == null; |
| } |
| |
| |
| // ********** pk ordering ********** |
| |
| public boolean isPkOrdering() { |
| return this.pkOrdering; |
| } |
| |
| public void setPkOrdering(boolean pkOrdering) { |
| if (pkOrdering) { |
| this.setSpecifiedOrderBy(""); //$NON-NLS-1$ |
| } else { |
| this.setNoOrdering(true); // hmmm... |
| } |
| } |
| |
| protected void setPkOrdering_(boolean pkOrdering) { |
| boolean old = this.pkOrdering; |
| this.pkOrdering = pkOrdering; |
| this.firePropertyChanged(PK_ORDERING_PROPERTY, old, pkOrdering); |
| } |
| |
| /** |
| * the order-by element is present but no value specified |
| */ |
| protected boolean buildPkOrdering() { |
| if (this.xmlOrderColumnIsPresent()) { |
| return false; |
| } |
| String xmlOrderBy = this.getXmlOrderBy(); |
| return (xmlOrderBy != null) && (xmlOrderBy.length() == 0); |
| } |
| |
| |
| // ********** custom ordering ********** |
| |
| public boolean isCustomOrdering() { |
| return this.customOrdering; |
| } |
| |
| /** |
| * Unfortunately, setting the "custom ordering" flag directly is a bit hacky: |
| * The "specified order-by" is initially set to an empty string, which is |
| * the same as a "primary key ordering" state.... |
| */ |
| public void setCustomOrdering(boolean customOrdering) { |
| if (customOrdering) { |
| this.setSpecifiedOrderBy_(""); // hmmm... //$NON-NLS-1$ |
| this.setNoOrdering_(false); |
| this.setPkOrdering_(false); |
| this.setCustomOrdering_(true); |
| this.setOrderColumnOrdering_(false); |
| |
| this.removeXmlOrderColumn(); |
| this.getXmlOrderable().setOrderBy(""); //$NON-NLS-1$ |
| } else { |
| this.setNoOrdering(true); // hmmm... |
| } |
| } |
| |
| protected void setCustomOrdering_(boolean customOrdering) { |
| boolean old = this.customOrdering; |
| this.customOrdering = customOrdering; |
| this.firePropertyChanged(CUSTOM_ORDERING_PROPERTY, old, customOrdering); |
| } |
| |
| /** |
| * the order-by element is present and it has a specified value |
| */ |
| protected boolean buildCustomOrdering() { |
| if (this.xmlOrderColumnIsPresent()) { |
| return false; |
| } |
| String xmlOrderBy = this.getXmlOrderBy(); |
| return (xmlOrderBy != null) && (xmlOrderBy.length() != 0); |
| } |
| |
| |
| // ********** order column ordering ********** |
| |
| public boolean isOrderColumnOrdering() { |
| return this.orderColumnOrdering; |
| } |
| |
| public void setOrderColumnOrdering(boolean orderColumnOrdering) { |
| if (orderColumnOrdering) { |
| this.setSpecifiedOrderBy_(null); |
| this.setNoOrdering_(false); |
| this.setPkOrdering_(false); |
| this.setCustomOrdering_(false); |
| this.setOrderColumnOrdering_(true); |
| |
| this.getXmlOrderable().setOrderBy(null); |
| this.buildXmlOrderColumn(); |
| } else { |
| this.setNoOrdering(true); // hmmm... |
| } |
| } |
| |
| protected void setOrderColumnOrdering_(boolean orderColumnOrdering) { |
| boolean old = this.orderColumnOrdering; |
| this.orderColumnOrdering = orderColumnOrdering; |
| this.firePropertyChanged(ORDER_COLUMN_ORDERING_PROPERTY, old, orderColumnOrdering); |
| } |
| |
| /** |
| * JPA 2.0 only; |
| * the <code>order-column</code> element is present <em>and</em> |
| * the <code>order-by</code> element is missing |
| */ |
| protected boolean buildOrderColumnOrdering() { |
| return this.xmlOrderColumnIsPresent() && |
| (this.getXmlOrderBy() == null); |
| } |
| |
| |
| // ********** order column ********** |
| |
| public OrmOrderColumn2_0 getOrderColumn() { |
| return this.orderColumn; |
| } |
| |
| /** |
| * JPA 2.0 only |
| */ |
| protected OrmOrderColumn2_0 buildOrderColumn() { |
| return this.isOrmXml2_0Compatible() ? |
| this.getContextNodeFactory2_0().buildOrmOrderColumn(this, new OrderColumnOwner()) : |
| null; |
| } |
| |
| |
| // ********** xml order by ********** |
| |
| protected String getXmlOrderBy() { |
| return this.getXmlOrderable().getOrderBy(); |
| } |
| |
| |
| // ********** xml order column ********** |
| |
| protected XmlOrderColumn getXmlOrderColumn() { |
| return this.getXmlOrderable().getOrderColumn(); |
| } |
| |
| /** |
| * NB: Only return <code>true</code> for JPA 2.0 mappings. |
| */ |
| protected boolean xmlOrderColumnIsPresent() { |
| return this.isJpa2_0Compatible() && (this.getXmlOrderColumn() != null); |
| } |
| |
| protected XmlOrderColumn buildXmlOrderColumn() { |
| XmlOrderColumn xmlColumn = OrmFactory.eINSTANCE.createXmlOrderColumn(); |
| GenericOrmOrderable.this.getXmlOrderable().setOrderColumn(xmlColumn); |
| return xmlColumn; |
| } |
| |
| protected void removeXmlOrderColumn() { |
| if (this.xmlOrderColumnIsPresent()) { |
| this.getXmlOrderable().setOrderColumn(null); |
| } |
| } |
| |
| |
| // ********** misc ********** |
| |
| @Override |
| public OrmAttributeMapping getParent() { |
| return (OrmAttributeMapping) super.getParent(); |
| } |
| |
| protected OrmAttributeMapping getAttributeMapping() { |
| return this.getParent(); |
| } |
| |
| protected OrmPersistentAttribute getPersistentAttribute() { |
| return this.getAttributeMapping().getPersistentAttribute(); |
| } |
| |
| protected XmlOrderable getXmlOrderable() { |
| return (XmlOrderable) this.getAttributeMapping().getXmlAttributeMapping(); |
| } |
| |
| // JPA 2.0 |
| public String getDefaultTableName() { |
| return this.owner.getTableName(); |
| } |
| |
| // JPA 2.0 |
| protected Table resolveDbTable(String tableName) { |
| return this.owner.resolveDbTable(tableName); |
| } |
| |
| |
| // ********** validation ********** |
| |
| public TextRange getValidationTextRange() { |
| TextRange textRange = this.getXmlOrderable().getValidationTextRange(); |
| return (textRange != null) ? textRange : this.getAttributeMapping().getValidationTextRange(); |
| } |
| |
| @Override |
| public void validate(List<IMessage> messages, IReporter reporter) { |
| super.validate(messages, reporter); |
| // order-column and order-by both specified is handled with schema validation |
| if (this.orderColumnOrdering) { |
| // TODO validation message if type is not List |
| this.orderColumn.validate(messages, reporter); |
| } |
| } |
| |
| // ********** completion proposals ********** |
| |
| @Override |
| public Iterable<String> getXmlCompletionProposals(int pos) { |
| Iterable<String> result = super.getXmlCompletionProposals(pos); |
| if (result != null) { |
| return result; |
| } |
| // orderColumn is null for JPA 1.0 mappings so adding a null |
| // check here to prevent NPE - Bug 375670 |
| if (this.orderColumn != null) { |
| result = this.orderColumn.getXmlCompletionProposals(pos); |
| if (result != null) { |
| return result; |
| } |
| } |
| return null; |
| } |
| |
| // ********** order column owner (JPA 2.0) ********** |
| |
| protected class OrderColumnOwner |
| implements OrmOrderColumn2_0.Owner |
| { |
| public String getDefaultTableName() { |
| return GenericOrmOrderable.this.getDefaultTableName(); |
| } |
| |
| public Table resolveDbTable(String tableName) { |
| return GenericOrmOrderable.this.resolveDbTable(tableName); |
| } |
| |
| public String getDefaultColumnName(ReadOnlyNamedColumn column) { |
| return this.getPersistentAttribute().getName() + "_ORDER"; //$NON-NLS-1$ |
| } |
| |
| public TextRange getValidationTextRange() { |
| return GenericOrmOrderable.this.getValidationTextRange(); |
| } |
| |
| public JptValidator buildColumnValidator(ReadOnlyNamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { |
| return new OrderColumnValidator(this.getPersistentAttribute(), (OrderColumn2_0) column, textRangeResolver); |
| } |
| |
| public XmlOrderColumn getXmlColumn() { |
| return GenericOrmOrderable.this.getXmlOrderColumn(); |
| } |
| |
| public XmlOrderColumn buildXmlColumn() { |
| return GenericOrmOrderable.this.buildXmlOrderColumn(); |
| } |
| |
| public void removeXmlColumn() { |
| GenericOrmOrderable.this.removeXmlOrderColumn(); |
| } |
| |
| protected OrmPersistentAttribute getPersistentAttribute() { |
| return GenericOrmOrderable.this.getPersistentAttribute(); |
| } |
| } |
| } |