blob: 91134492c393eccdacc911362296c8ab32f2e670 [file] [log] [blame]
gkessler185eba92007-01-24 17:22:47 +00001/*******************************************************************************
2 * Copyright (c) 2007 Oracle Corporation.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Oracle - initial API and implementation
10 *
11 ********************************************************************************/
12package org.eclipse.jst.jsf.common.metadata.internal;
13
gkesslerc2f5b4d2007-02-07 00:04:40 +000014import java.util.Iterator;
15
gkessler53e15ba2007-06-11 20:55:59 +000016import org.eclipse.core.runtime.IStatus;
gkessler185eba92007-01-24 17:22:47 +000017import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
gkessler53e15ba2007-06-11 20:55:59 +000018import org.eclipse.jst.jsf.common.JSFCommonPlugin;
itrimble7dafed72007-04-16 19:55:20 +000019import org.eclipse.jst.jsf.common.metadata.Entity;
20import org.eclipse.jst.jsf.common.metadata.EntityGroup;
21import org.eclipse.jst.jsf.common.metadata.IncludeEntityGroup;
22import org.eclipse.jst.jsf.common.metadata.Model;
23import org.eclipse.jst.jsf.common.metadata.Trait;
gkessler53e15ba2007-06-11 20:55:59 +000024import org.eclipse.jst.jsf.common.metadata.query.ITaglibDomainMetaDataModelContext;
gkessler82a75582007-05-16 23:51:15 +000025import org.eclipse.jst.jsf.common.metadata.query.MetaDataException;
gkessler53e15ba2007-06-11 20:55:59 +000026import org.eclipse.jst.jsf.common.metadata.query.TaglibDomainMetaDataQueryHelper;
gkessler82a75582007-05-16 23:51:15 +000027import org.eclipse.jst.jsf.common.metadata.query.internal.SearchControl;
28import org.eclipse.jst.jsf.common.metadata.query.internal.SimpleEntityQueryVisitorImpl;
29import org.eclipse.jst.jsf.common.metadata.query.internal.SimpleResultSet;
30import org.eclipse.jst.jsf.common.metadata.query.internal.SimpleTraitQueryVisitorImpl;
31import org.eclipse.jst.jsf.common.metadata.query.internal.HierarchicalSearchControl;
gkessler185eba92007-01-24 17:22:47 +000032/**
33 * Implements {@link IMetaDataModelMergeAssistant}
34 *
35 * Responsible for merging source models into one. The first model in has subsequent
36 * entities and traits added to it.
37 *
gkesslerc2f5b4d2007-02-07 00:04:40 +000038 * TODO - make locating of existing entities and traits in the merged model more efficient
gkesslercbf73222007-06-12 21:41:43 +000039 * TODO - refactor out Taglibdomain-only aspects of include-group processing
gkessler185eba92007-01-24 17:22:47 +000040 *
41 */
42public class MetaDataModelMergeAssistantImpl implements
43 IMetaDataModelMergeAssistant {
44
45 private MetaDataModel mergedModel;
gkessler185eba92007-01-24 17:22:47 +000046 private Copier copier;
gkessler82a75582007-05-16 23:51:15 +000047 private SimpleEntityQueryVisitorImpl entityVisitor;
48 private SimpleTraitQueryVisitorImpl traitVisitor;
gkessler510d92b2007-02-28 05:04:50 +000049 private IMetaDataSourceModelProvider provider;
gkessler185eba92007-01-24 17:22:47 +000050
51 /**
gkessler82a75582007-05-16 23:51:15 +000052 * Constructor. Queries with search control limited to first found.
gkessler185eba92007-01-24 17:22:47 +000053 * @param model
54 */
55 public MetaDataModelMergeAssistantImpl(MetaDataModel model) {
56 this.mergedModel = model;
57 copier = new Copier();
gkesslercbf73222007-06-12 21:41:43 +000058 entityVisitor = new SimpleEntityQueryVisitorImpl(new HierarchicalSearchControl(1,
59 HierarchicalSearchControl.SCOPE_ALL_LEVELS));
gkessler82a75582007-05-16 23:51:15 +000060 traitVisitor = new SimpleTraitQueryVisitorImpl(new SearchControl(1));
gkessler185eba92007-01-24 17:22:47 +000061 }
62
63 /* (non-Javadoc)
64 * @see org.eclipse.jst.jsf.common.metadata.internal.IMetaDataModelMergeAssistant#getMergedModel()
65 */
66 public MetaDataModel getMergedModel() {
67 return mergedModel;
68 }
69
70 /* (non-Javadoc)
71 * @see org.eclipse.jst.jsf.common.metadata.internal.IMetaDataModelMergeAssistant#getSourceModel()
72 */
gkessler510d92b2007-02-28 05:04:50 +000073 public IMetaDataSourceModelProvider getSourceModelProvider() {
74 return provider;
gkessler185eba92007-01-24 17:22:47 +000075 }
76
gkessler510d92b2007-02-28 05:04:50 +000077 public void setSourceModelProvider(IMetaDataSourceModelProvider provider) {
78 this.provider = provider;
gkessler185eba92007-01-24 17:22:47 +000079 }
80
gkesslerc2f5b4d2007-02-07 00:04:40 +000081
82 /* (non-Javadoc)
itrimble7ecc4d52007-04-18 21:07:11 +000083 * @see org.eclipse.jst.jsf.common.metadata.internal.IMetaDataModelMergeAssistant#addEntityGroup(org.eclipse.jst.jsf.common.metadata.EntityGroup)
gkesslerc2f5b4d2007-02-07 00:04:40 +000084 */
85 public void addEntityGroup(EntityGroup entityGroup) {
86 Model model = (Model)getMergedModel().getRoot();
87 if (!isExistingEntityGroup(model, entityGroup)){
88 model.getEntityGroups().add(entityGroup);
89 }
90 }
91
gkessler185eba92007-01-24 17:22:47 +000092 /* (non-Javadoc)
itrimble7ecc4d52007-04-18 21:07:11 +000093 * @see org.eclipse.jst.jsf.common.metadata.internal.IMetaDataModelMergeAssistant#addEntity(org.eclipse.jst.jsf.common.metadata.Entity)
gkessler185eba92007-01-24 17:22:47 +000094 */
gkesslerc2f5b4d2007-02-07 00:04:40 +000095 public boolean addEntity(final Entity entity) {
gkessler185eba92007-01-24 17:22:47 +000096 Entity mmEntity = getMergedEntity(entity);
97 if (mmEntity == null){
gkesslerc2f5b4d2007-02-07 00:04:40 +000098 addEntityAsNecessary((Entity)entity.eContainer(), entity);
gkessler185eba92007-01-24 17:22:47 +000099 return true;
100 }
gkesslerc2f5b4d2007-02-07 00:04:40 +0000101 addIncludeGroupsAsNecessary(mmEntity, entity);
gkessler185eba92007-01-24 17:22:47 +0000102 return false;
103 }
104
gkesslerc2f44ec2007-12-07 23:43:50 +0000105 public Entity getMergedEntity(Entity queryRoot, String entityKey){
106 Entity ret = null;
107 SimpleResultSet rs = (SimpleResultSet)entityVisitor.findEntities(queryRoot, entityKey);
108 try {
109 if (! rs.getResults().isEmpty())
110 ret = (Entity)rs.getResults().get(0);
111 rs.close();
112 } catch (MetaDataException e) {
gkesslercfc53082008-11-18 22:25:04 +0000113 JSFCommonPlugin.log(IStatus.ERROR, "Error in getMergedEntity()", e); //$NON-NLS-1$
gkesslerc2f44ec2007-12-07 23:43:50 +0000114 }
115 return ret;
116 }
gkesslerc2f5b4d2007-02-07 00:04:40 +0000117 private void addIncludeGroupsAsNecessary(final Entity mmEntity, final Entity entity) {
118 for (Iterator it=entity.getIncludeGroups().iterator();it.hasNext();){
119 IncludeEntityGroup grp = (IncludeEntityGroup)it.next();
120 boolean found = false;
121 for (Iterator it2=mmEntity.getIncludeGroups().iterator();it2.hasNext();){
122 IncludeEntityGroup grp2 = (IncludeEntityGroup)it2.next();
123 if (grp2.equals(grp)){
124 found = true;
125 break;
126 }
127 }
128 if (!found){//maybe we should clone and add
129 mmEntity.getIncludeGroups().add(grp);
130 }
131 }
132 }
133
gkessler185eba92007-01-24 17:22:47 +0000134 /**
135 * Checks to see if the entity (by id) is present in the mergedModel or not.
136 * If not, it will perform a copy of the entity and it's attributes using
137 * EcoreUtil.Copier.
gkessler185eba92007-01-24 17:22:47 +0000138 *
139 * @param parent
140 * @param entity
141 * @return
142 */
143 private Entity addEntityAsNecessary(final Entity parent, final Entity entity) {
144 Entity mmParent = null;
145 Entity mmEntity = null;
146 if (parent != null){
147 mmParent = getMergedEntity(parent);
148 if (mmParent == null){
gkesslerc2f5b4d2007-02-07 00:04:40 +0000149 mmParent = addEntityAsNecessary((Entity)entity.eContainer(), entity);
gkessler185eba92007-01-24 17:22:47 +0000150 }
151 }
152 if (mmParent != null){
gkesslerc2f5b4d2007-02-07 00:04:40 +0000153 mmEntity = addEntityInternal(mmParent, entity);
gkessler185eba92007-01-24 17:22:47 +0000154 return mmEntity;
155 }
156 return mmEntity;
157 }
gkesslerc2f5b4d2007-02-07 00:04:40 +0000158
159 private boolean isExistingEntityGroup(Model model, EntityGroup entityGroup) {
160 boolean found = false;
161 for(Iterator it=model.getEntityGroups().iterator();it.hasNext();){
162 if (entityGroup.getId().equals(((EntityGroup)it.next()).getId()))
163 return true;
164 }
165 return found;
166 }
167
gkesslercbf73222007-06-12 21:41:43 +0000168 private Entity getExistingChildEntity(final Entity parent, final Entity entity) {
gkesslerc2f5b4d2007-02-07 00:04:40 +0000169 for(Iterator it=parent.getChildEntities().iterator();it.hasNext();){
gkesslercbf73222007-06-12 21:41:43 +0000170 Entity foundEntity = (Entity)it.next();
171 if (entity.getId().equals(foundEntity.getId()))
172 return foundEntity;
gkesslerc2f5b4d2007-02-07 00:04:40 +0000173 }
gkesslercbf73222007-06-12 21:41:43 +0000174 return null;
gkesslerc2f5b4d2007-02-07 00:04:40 +0000175 }
176
gkesslercbf73222007-06-12 21:41:43 +0000177 private /*synchronized*/ Entity addEntityInternal(final Entity parent, final Entity entity) {
cbateman4a2fa1e2007-03-22 23:54:07 +0000178 Entity mmEntity =(Entity)copier.copy(entity);
gkesslerc2f5b4d2007-02-07 00:04:40 +0000179 copier.copyReferences();
180 parent.getChildEntities().add(mmEntity);
181 return mmEntity;
182 }
gkessler185eba92007-01-24 17:22:47 +0000183
184 /* (non-Javadoc)
itrimble7ecc4d52007-04-18 21:07:11 +0000185 * @see org.eclipse.jst.jsf.common.metadata.internal.IMetaDataModelMergeAssistant#addTrait(org.eclipse.jst.jsf.common.metadata.Entity, org.eclipse.jst.jsf.common.metadata.Trait)
gkessler185eba92007-01-24 17:22:47 +0000186 */
187 public boolean addTrait(Entity entity, Trait trait) {
188 Entity returnedEntity = getMergedEntity(entity);
189 if (returnedEntity != null){
gkesslerc2f5b4d2007-02-07 00:04:40 +0000190 return addTraitAsNecessary(returnedEntity, trait);
191 }
192 return false;
193 }
194
gkessler185eba92007-01-24 17:22:47 +0000195
gkesslerc2f5b4d2007-02-07 00:04:40 +0000196 private boolean addTraitAsNecessary(Entity mergedEntity, Trait trait) {
197 Trait mmTrait = getMergedTrait(mergedEntity, trait);
198 if (mmTrait == null){
gkessleraa43c772008-09-03 23:29:04 +0000199 addTraitInternal(mergedEntity, trait);
gkesslerc2f5b4d2007-02-07 00:04:40 +0000200 return true;
201
gkessler185eba92007-01-24 17:22:47 +0000202 }
203 return false;
204 }
205
gkesslerc2f5b4d2007-02-07 00:04:40 +0000206 /* (non-Javadoc)
207 * @see org.eclipse.jst.jsf.common.metadata.internal.IMetaDataModelMergeAssistant#setMergeComplete()
208 */
209 public void setMergeComplete() {
210 Model model = (Model)getMergedModel().getRoot();
gkessleraa43c772008-09-03 23:29:04 +0000211 if (model != null){
gkesslercfc53082008-11-18 22:25:04 +0000212 StandardModelFactory.debug(">> Begin processIncludeGroups for: "+getMergedModel().getModelKey(),StandardModelFactory.DEBUG_MD_LOAD); //$NON-NLS-1$
gkessleraa43c772008-09-03 23:29:04 +0000213
214 processIncludeGroups(model);
215
gkesslercfc53082008-11-18 22:25:04 +0000216 StandardModelFactory.debug(">> End processIncludeGroups for: "+getMergedModel().getModelKey(),StandardModelFactory.DEBUG_MD_LOAD); //$NON-NLS-1$
gkessleraa43c772008-09-03 23:29:04 +0000217 }
gkesslerc2f5b4d2007-02-07 00:04:40 +0000218 }
219
gkessler185eba92007-01-24 17:22:47 +0000220 /**
221 * Copies the passed trait and adds it to the merged entity.
gkesslerc2f5b4d2007-02-07 00:04:40 +0000222 * The source model provider of the trait is then set on the trait so that
gkessler185eba92007-01-24 17:22:47 +0000223 * the trait can know where it came from.
224 *
225 * @param parent
226 * @param trait
227 * @return merged Trait
228 */
229 private Trait addTraitInternal(final Entity parent, final Trait trait) {
cbateman4a2fa1e2007-03-22 23:54:07 +0000230 Trait mmTrait =(Trait)copier.copy(trait);
gkesslerc2f5b4d2007-02-07 00:04:40 +0000231 copier.copyReferences();
gkessler185eba92007-01-24 17:22:47 +0000232 parent.getTraits().add(mmTrait);
233 //set the model key to know from where the trait came
gkessler510d92b2007-02-28 05:04:50 +0000234 mmTrait.setSourceModelProvider(trait.getSourceModelProvider());
gkessler185eba92007-01-24 17:22:47 +0000235 return mmTrait;
236 }
237
238 /**
239 * Locates the entity in the merged model matching by id only.
gkesslercbf73222007-06-12 21:41:43 +0000240 * If not located, this method returns null;
gkessler185eba92007-01-24 17:22:47 +0000241 *
242 * @param entity
243 * @return merged entity
244 */
gkesslercbf73222007-06-12 21:41:43 +0000245 private Entity getMergedEntity(Entity entity){
gkessler185eba92007-01-24 17:22:47 +0000246 if (entity instanceof Model)
247 return (Entity)mergedModel.getRoot();
248
249 Entity ret = null;
250 String entityKey = getIdRelativeToRoot(entity);
gkessler82a75582007-05-16 23:51:15 +0000251 SimpleResultSet rs = (SimpleResultSet)entityVisitor.findEntities((Entity)mergedModel.getRoot(), entityKey);
gkessler53e15ba2007-06-11 20:55:59 +0000252 try {
253 if (! rs.getResults().isEmpty())
254 ret = (Entity)rs.getResults().get(0);
255 rs.close();
256 } catch (MetaDataException e) {
gkesslercfc53082008-11-18 22:25:04 +0000257 JSFCommonPlugin.log(IStatus.ERROR, "Error in getMergedEntity()", e); //$NON-NLS-1$
gkessler82a75582007-05-16 23:51:15 +0000258 }
gkessler185eba92007-01-24 17:22:47 +0000259 return ret;
260 }
261
262 private String getIdRelativeToRoot(final Entity entity) {
263 Entity e = entity;
264 StringBuffer buf = new StringBuffer();
gkesslerc2f5b4d2007-02-07 00:04:40 +0000265 while (e.eContainer() != null){
266 buf.insert(0, e.getId());
267 if (e.eContainer()!=null && e.eContainer().eContainer() != null)
gkesslercfc53082008-11-18 22:25:04 +0000268 buf.insert(0,"/"); //$NON-NLS-1$
gkesslerc2f5b4d2007-02-07 00:04:40 +0000269 e = (Entity)e.eContainer();
gkessler185eba92007-01-24 17:22:47 +0000270 }
271 return buf.toString();
272 }
273
274 /**
275 * Locates the trait in the merged model matching by id only.
276 * If not located, this method returns null;
277 *
278 * @param entity
279 * @param trait
280 * @return merged Trait
281 */
282 public Trait getMergedTrait(Entity entity, Trait trait){
gkessler82a75582007-05-16 23:51:15 +0000283 SimpleResultSet rs = (SimpleResultSet)traitVisitor.findTraits(entity, trait.getId());
gkessler185eba92007-01-24 17:22:47 +0000284 Trait ret = null;
gkessler53e15ba2007-06-11 20:55:59 +0000285 try {
286 if (! rs.getResults().isEmpty())
287 ret = (Trait)rs.getResults().get(0);
288 rs.close();
289 } catch (MetaDataException e) {
gkesslercfc53082008-11-18 22:25:04 +0000290 JSFCommonPlugin.log(IStatus.ERROR, "Error in getMergedTrait()", e); //$NON-NLS-1$
gkessler82a75582007-05-16 23:51:15 +0000291 }
gkessler185eba92007-01-24 17:22:47 +0000292 return ret;
293 }
gkessler82a75582007-05-16 23:51:15 +0000294
gkesslerc2f5b4d2007-02-07 00:04:40 +0000295 private void processIncludeGroups(final Model root) {
cbateman4a2fa1e2007-03-22 23:54:07 +0000296 addEntityGroupReferencesRecursively(root);
gkesslerc2f5b4d2007-02-07 00:04:40 +0000297 }
298
299 private void addEntityGroupReferencesRecursively(final Entity entity) {
300 doIncludes(entity);
301 for (int i=0, size=entity.getChildEntities().size();i<size;i++){
302 addEntityGroupReferencesRecursively((Entity)entity.getChildEntities().get(i));
303 }
304 }
305
306 private void doIncludes(final Entity entity){
307 for (int j=0, groupsSize=entity.getIncludeGroups().size();j<groupsSize; j++){
308 IncludeEntityGroup include = (IncludeEntityGroup)entity.getIncludeGroups().get(j);
309 if (include.getId() != null){
310 //is this a local merge?
gkesslercbf73222007-06-12 21:41:43 +0000311 if (include.getModelUri() == null||
312 (include.getModelUri()
313 .equals(getMergedModel()
314 .getModelKey().getUri())) ){
gkesslerc2f5b4d2007-02-07 00:04:40 +0000315 EntityGroup eg = ((Model)getMergedModel().getRoot()).findIncludeGroup(include.getId());
316 addIncludeRefs(entity, eg);
317 } else //external model include
318 addIncludeRefs(entity, include);
319 }
320 }
321 }
322 /*
323 * Adds traits and child entities from an external entity group to the passed entity
324 * @param entity
325 * @param include
326 */
327 private void addIncludeRefs(final Entity entity, final IncludeEntityGroup include) {
gkessler53e15ba2007-06-11 20:55:59 +0000328 ITaglibDomainMetaDataModelContext modelContext = new TaglibDomainMetaDataModelContextImpl(
329 getMergedModel().getModelKey().getDomain(),
330 getMergedModel().getModelKey().getProject(),
331 include.getModelUri()
332 );
gkesslerc2f5b4d2007-02-07 00:04:40 +0000333
gkessler53e15ba2007-06-11 20:55:59 +0000334 Model externalModel = TaglibDomainMetaDataQueryHelper.getModel(modelContext);
gkessler4c8bd022008-02-01 20:21:15 +0000335 if (externalModel != null){
336 EntityGroup entityGroup = externalModel.findIncludeGroup(include.getId());
337 addIncludeRefs(entity, entityGroup);
338 }
339 else {
gkesslercfc53082008-11-18 22:25:04 +0000340 JSFCommonPlugin.log(IStatus.ERROR, "Unable to load external metadata model refs for "+modelContext.getURI() //$NON-NLS-1$
341 + " into "+ entity.getModel().getCurrentModelContext().getUri()); //$NON-NLS-1$
gkessler4c8bd022008-02-01 20:21:15 +0000342 }
gkesslerc2f5b4d2007-02-07 00:04:40 +0000343 }
344
345 /*
346 * Adds traits and child entities from a local entity group to the passed entity if not already present for the entity.
347 * First
348 * @param entity
349 * @param entityGroup
350 */
351 private void addIncludeRefs(final Entity entity, final EntityGroup entityGroup) {
352 if (entityGroup == null)
353 return;
354
355 for (int i=0, size=entityGroup.getTraits().size();i<size;i++){
gkesslercbf73222007-06-12 21:41:43 +0000356 addTrait(entity, (Trait)entityGroup.getTraits().get(i));
gkesslerc2f5b4d2007-02-07 00:04:40 +0000357 }
358
359 for (int i=0, size=entityGroup.getChildEntities().size();i<size;i++){
gkesslercbf73222007-06-12 21:41:43 +0000360 traverseAndAddIncludes(entity, (Entity)entityGroup.getChildEntities().get(i));
gkesslerc2f5b4d2007-02-07 00:04:40 +0000361 }
362 }
363
gkesslercbf73222007-06-12 21:41:43 +0000364 private void traverseAndAddIncludes(final Entity parent, final Entity entity){
365 Entity mergedEntity = addIncludedEntityAsNecessary(parent, entity);
366
367 for (final Iterator/*<Trait>*/ it=entity.getTraits().iterator();it.hasNext();){
368 Trait trait = (Trait)it.next();
369 addTraitAsNecessary(mergedEntity, trait);
370 }
371
372 for (final Iterator/*<EntityKey>*/ it=entity.getChildEntities().iterator();it.hasNext();){
373 Entity e = (Entity)it.next();
374 traverseAndAddIncludes(mergedEntity, e);//add as normal
375 }
376
377 }
378
gkesslerc2f5b4d2007-02-07 00:04:40 +0000379 /*
380 * Checks to see if the entity (by id) is present as a child entity in the parent or not.
gkesslercbf73222007-06-12 21:41:43 +0000381 * If not, it will add the entity to the childEntities without copying.
gkesslerc2f5b4d2007-02-07 00:04:40 +0000382 *
383 * @param parent
384 * @param entity
gkesslercbf73222007-06-12 21:41:43 +0000385 * @return Entity
gkesslerc2f5b4d2007-02-07 00:04:40 +0000386 */
gkesslercbf73222007-06-12 21:41:43 +0000387 private Entity addIncludedEntityAsNecessary(final Entity parent, final Entity entity) {
388 Entity mergedEntity = getExistingChildEntity(parent, entity);
389 if (mergedEntity == null){
390 mergedEntity = addEntityInternal(parent, entity);
gkesslerc2f5b4d2007-02-07 00:04:40 +0000391 }
gkesslercbf73222007-06-12 21:41:43 +0000392 return mergedEntity;
gkesslerc2f5b4d2007-02-07 00:04:40 +0000393 }
394
gkessler185eba92007-01-24 17:22:47 +0000395}