]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.objmap2/src/org/simantics/objmap/graph/impl/Mapping.java
Use trace level debug messages with ObjMap
[simantics/platform.git] / bundles / org.simantics.objmap2 / src / org / simantics / objmap / graph / impl / Mapping.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2013 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.objmap.graph.impl;
13
14
15 import gnu.trove.map.hash.THashMap;
16
17 import java.util.AbstractSet;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Set;
23
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 import org.simantics.db.ReadGraph;
27 import org.simantics.db.WriteGraph;
28 import org.simantics.db.exception.DatabaseException;
29
30 import org.simantics.objmap.backward.IBackwardMapping;
31 import org.simantics.objmap.exceptions.MappingException;
32 import org.simantics.objmap.forward.IForwardMapping;
33 import org.simantics.objmap.graph.IMapping;
34 import org.simantics.objmap.graph.IMappingListener;
35 import org.simantics.objmap.graph.schema.ILinkType;
36 import org.simantics.objmap.graph.schema.IMappingSchema;
37
38 /**
39  * An implementation of IMapping. The class should not be created
40  * directly but using methods in Mappings.
41  * @see org.simantics.objmap.graph.Mappings
42  * @author Hannu Niemistö
43  */
44 public class Mapping<Domain, Range> implements IMapping<Domain, Range> {
45
46         static final Logger LOGGER = LoggerFactory.getLogger(Mapping.class);
47         
48         
49         IMappingSchema<Domain, Range> schema;
50         
51         THashMap<Domain, Link<Domain,Range>> domain = new THashMap<Domain, Link<Domain,Range>>();
52         THashMap<Range, Link<Domain,Range>> range = new THashMap<Range, Link<Domain,Range>>();
53         ArrayList<IMappingListener> listeners = new ArrayList<IMappingListener>();
54
55         ArrayList<Link<Domain,Range>> modifiedDomainLinks = new ArrayList<Link<Domain,Range>>();
56         ArrayList<Link<Domain,Range>> modifiedRangeLinks = new ArrayList<Link<Domain,Range>>();
57
58         boolean disposed = false;
59         
60         boolean listensDomain; 
61         
62         public Mapping(IMappingSchema<Domain, Range> schema, boolean listensDomain) {
63                 this.schema = schema;
64                 this.listensDomain = listensDomain;
65         }
66         
67         private void removeLink(Link<Domain,Range> link) {
68                 if(link.domainModified)
69                         modifiedDomainLinks.remove(link);
70                 if(link.rangeModified)
71                         modifiedRangeLinks.remove(link);
72                 link.removed = true;
73         }
74         
75         private void createDomain(WriteGraph g, Link<Domain,Range> link) throws MappingException {
76             LOGGER.trace("        createDomain for " + link.rangeElement);
77                 ILinkType<Domain,Range> type = schema.linkTypeOfRangeElement(link.rangeElement);
78                 Domain domainElement = type.createDomainElement(g, link.rangeElement);
79                 link.type = type;
80                 link.domainElement = domainElement;
81                 domain.put(domainElement, link);
82                 type.createDomain(g, new RangeToDomain(g), domainElement, link.rangeElement);
83                 
84         // TODO Should we do this only if the mapping is listening?
85         domainModified(link);
86         }
87         
88         private void createRange(ReadGraph g, Link<Domain,Range> link) throws MappingException {
89                 ILinkType<Domain,Range> type = schema.linkTypeOfDomainElement(g, link.domainElement);           
90                 Range rangeElement = type.createRangeElement(g, link.domainElement);
91                 
92                 link.type = type;
93                 link.rangeElement = rangeElement;
94                 range.put(rangeElement, link);
95                 type.createRange(g, new DomainToRange(g), link.domainElement, rangeElement);
96         }
97         
98         Set<Domain> domainSet = new AbstractSet<Domain>() {
99
100                 public boolean add(Domain e) {
101                         if(domain.containsKey(e))
102                                 return false;
103                         Link<Domain,Range> link = new Link<Domain,Range>(null, e, null);
104                         domain.put(e, link);
105                         modifiedDomainLinks.add(link);
106                         return true;
107                 }
108                 
109                 public boolean contains(Object o) {
110                         return domain.contains(o);
111                 }
112                 
113                 public boolean remove(Object o) {
114                         Link<Domain,Range> link = domain.remove(o);                     
115                         if(link == null)
116                                 return false;
117                         removeLink(link);
118                         if(link.rangeElement != null)
119                                 range.remove(link.rangeElement);
120                         return true;    
121                 }
122                 
123                 @Override
124                 public Iterator<Domain> iterator() {
125                     // FIXME does not implement Iterator.remove correctly
126                         return domain.keySet().iterator();
127                 }
128
129                 @Override
130                 public int size() {
131                         return domain.size();
132                 }
133                 
134         };
135         
136         Set<Range> rangeSet = new AbstractSet<Range>() {
137
138                 public boolean add(Range e) {
139                         if(range.containsKey(e))
140                                 return false;
141                         Link<Domain,Range> link = new Link<Domain,Range>(null, null, e);
142                         range.put(e, link);
143                         modifiedRangeLinks.add(link);
144                         return true;
145                 }
146                 
147                 public boolean contains(Object o) {
148                         return range.contains(o);
149                 }
150                 
151                 public boolean remove(Object o) {
152                         Link<Domain,Range> link = range.remove(o);                      
153                         if(link == null)
154                                 return false;
155                         removeLink(link);
156                         if(link.domainElement != null)
157                                 domain.remove(link.domainElement);
158                         return true;
159                 }
160                 
161                 @Override
162                 public Iterator<Range> iterator() {
163                     // FIXME does not implement Iterator.remove correctly
164                         return range.keySet().iterator();
165                 }
166
167                 @Override
168                 public int size() {
169                         return range.size();
170                 }
171                 
172         };
173         
174         class DomainToRange implements IForwardMapping<Domain, Range> {
175
176                 ReadGraph g;
177                 
178                 public DomainToRange(ReadGraph g) {
179                         this.g = g;
180                 }
181
182                 @Override
183                 public Range get(Domain element)  {
184                         Link<Domain,Range> link = domain.get(element);
185                         if (link != null)
186                                 return link.rangeElement;
187                         return null;
188                         
189                 }
190                 
191                 @Override
192                 public Range map(ReadGraph graph, Domain element)
193                                 throws MappingException {
194                         Link<Domain,Range> link = domain.get(element);
195                         if(link == null) {
196                             link = new Link<Domain,Range>(null, element, null);
197                     link.domainModified = true;
198                     modifiedDomainLinks.add(link);
199                             domain.put(element, link);           
200                             createRange(g, link);       
201                         }
202                         else if(link.type == null) 
203                                 createRange(g, link);
204             return link.rangeElement;
205                 }
206                 
207                 @Override
208                 public Set<Domain> getDomain() {
209                         return domain.keySet();
210                 }
211                 
212         };
213         
214         class RangeToDomain extends DomainToRange implements IBackwardMapping<Domain, Range> {
215
216                 WriteGraph g;
217                 
218                 public RangeToDomain(WriteGraph g) {
219                         super(g);
220                         this.g = g;
221                 }
222                 @Override
223                 public Domain inverseGet(Range element) {
224                         
225                         Link<Domain,Range> link = range.get(element);
226                         if(link != null)
227                                 return link.domainElement;
228                         return null;
229                 }
230                 
231                 @Override
232                 public Domain inverseMap(WriteGraph graph, Range element)
233                                 throws MappingException {
234                         Link<Domain,Range> link = range.get(element);
235                         if(link == null) {
236                             link = new Link<Domain,Range>(null, null, element);
237                             link.rangeModified = true;
238                 modifiedRangeLinks.add(link);
239                             range.put(element, link);
240                             createDomain(g, link);                              
241                         }
242                         else if(link.type == null)
243                                 createDomain(g, link);
244                         return link.domainElement;
245                 }
246                 
247                 
248                 @Override
249                 public Set<Range> getRange() {
250                         return range.keySet();
251                 }
252         };
253         
254         @Override
255         public Set<Domain> getDomain() {
256                 return domainSet;
257         }
258         
259         @Override
260         public Set<Range> getRange() {
261                 return rangeSet;
262         }
263         
264         
265         @Override
266         public synchronized Collection<Domain> updateDomain(WriteGraph g) throws MappingException {
267             LOGGER.trace("Mapping.updateDomain");
268                 RangeToDomain map = new RangeToDomain(g);
269                 ArrayList<Domain> updated = new ArrayList<Domain>();
270                 while(!modifiedRangeLinks.isEmpty()) {
271                     LOGGER.trace("    modifiedRangeLinks.size() = " + modifiedRangeLinks.size());
272                     
273                         Link<Domain,Range> link = modifiedRangeLinks.remove(modifiedRangeLinks.size()-1);
274                         link.rangeModified = false;
275                         /*if(link.domainModified) {
276                                 link.domainModified = false;
277                                 modifiedDomainLinks.remove(link);
278                         }*/
279                         
280                         if(link.type == null) {
281                                 createDomain(g, link);
282                         }
283                         else {
284                                 if(link.type.updateDomain(g, map, link.domainElement, link.rangeElement))
285                                         updated.add(link.domainElement);
286                         }
287                 }       
288                 if (listensDomain)
289                         updateRange(g); //FIXME: without this listening would stop. 
290                 return updated;
291         }
292         
293         @Override
294         public synchronized Collection<Range> updateRange(ReadGraph g) throws MappingException {
295             LOGGER.trace("Mapping.updateRange");
296                 DomainToRange map = new DomainToRange(g);
297                 ArrayList<Range> updated = new ArrayList<Range>();
298                 while(!modifiedDomainLinks.isEmpty()) {             
299                     LOGGER.trace("    modifiedDomainLinks.size() = " + modifiedDomainLinks.size());
300                     
301                         Link<Domain,Range> link = modifiedDomainLinks.remove(modifiedDomainLinks.size()-1);
302                         link.domainModified = false;
303                         /*if(link.rangeModified) {
304                                 link.rangeModified = false;
305                                 modifiedRangeLinks.remove(link);
306                         }*/
307                         
308                         if(link.type == null) {
309                                 createRange(g, link);
310                         }
311                         
312                         if(listensDomain) {
313                             RangeUpdateRequest<Domain,Range> request = new RangeUpdateRequest<Domain,Range>(link, map, this);
314                             try {
315                     g.syncRequest(request, request);
316                 } catch (DatabaseException e) {
317                     throw new MappingException(e);
318                 }
319                             // TODO check if really modified
320                             updated.add(link.rangeElement);
321                         }
322                         else
323                             if(link.type.updateRange(g, map, link.domainElement, link.rangeElement))
324                                 updated.add(link.rangeElement);
325                 }       
326                 return updated;
327         }
328
329         @Override
330         public Range get(Domain domainElement) {
331                 Link<Domain,Range> link = domain.get(domainElement);
332                 if(link == null)
333                         return null;
334                 return link.rangeElement;
335         }
336
337         @Override
338         public Domain inverseGet(Range rangeElement) {
339                 Link<Domain,Range> link = range.get(rangeElement);
340                 if(link == null)
341                         return null;
342                 return link.domainElement;
343         }
344
345         @Override
346         public Domain inverseMap(WriteGraph g, Range rangeElement) throws MappingException {
347                 getRange().add(rangeElement);
348                 updateDomain(g);
349                 return inverseGet(rangeElement);
350         }
351
352         @Override
353         public Range map(ReadGraph g, Domain domainElement) throws MappingException {
354                 getDomain().add(domainElement);
355                 updateRange(g);
356                 return get(domainElement);
357         }
358
359         void domainModified(Link<Domain,Range> link) {
360             if(!link.domainModified) {          
361                 synchronized(modifiedDomainLinks) {
362                     LOGGER.trace("        domainModified for " + link.rangeElement);
363                 link.domainModified = true;
364                 modifiedDomainLinks.add(link);
365                 if(modifiedDomainLinks.size() == 1) {
366                     for(IMappingListener listener : listeners)
367                         listener.domainModified();
368                 }
369                 }
370         }
371         }
372         
373         @Override
374         public void domainModified(Domain domainElement) {
375                 Link<Domain,Range> link = domain.get(domainElement);
376                 if(link != null)
377                     domainModified(link);
378         }
379
380         void rangeModified(Link<Domain,Range> link) {
381             if(!link.rangeModified) {
382                 synchronized(modifiedRangeLinks) {
383                 link.rangeModified = true;
384                 modifiedRangeLinks.add(link);
385                 if(modifiedRangeLinks.size() == 1) {
386                     for(IMappingListener listener : listeners)
387                         listener.rangeModified();
388                 }
389                 }
390         }
391         }
392         
393         @Override
394         public void rangeModified(Range rangeElement) {
395                 Link<Domain,Range> link = range.get(rangeElement);
396                 if(link != null)
397                     rangeModified(link);
398         }
399
400         @Override
401         public boolean isDomainModified() {
402                 return !modifiedDomainLinks.isEmpty();
403         }
404
405         @Override
406         public boolean isRangeModified() {
407                 return !modifiedRangeLinks.isEmpty();
408         }
409         
410         @Override
411         public Collection<Domain> getDomainModified() {
412                 List<Domain> list = new ArrayList<Domain>(modifiedDomainLinks.size());
413                 for (Link<Domain, Range> link : modifiedDomainLinks)
414                         list.add(link.domainElement);
415                 return list;
416                                 
417         }
418         
419         @Override
420         public Collection<Range> getRangeModified() {
421                 List<Range> list = new ArrayList<Range>(modifiedRangeLinks.size());
422                 for (Link<Domain, Range> link : modifiedRangeLinks)
423                         list.add(link.rangeElement);
424                 return list;
425         }
426
427         @Override
428         public void addMappingListener(IMappingListener listener) {
429                 listeners.add(listener);
430         }
431
432         @Override
433         public void removeMappingListener(IMappingListener listener) {
434                 listeners.remove(listener);             
435         }
436
437         @Override
438         public Collection<Domain> getConflictingDomainElements() {
439                 ArrayList<Domain> result = new ArrayList<Domain>();
440                 if(modifiedDomainLinks.size() < modifiedRangeLinks.size()) {
441                         for(Link<Domain,Range> link : modifiedDomainLinks)
442                                 if(link.rangeModified)
443                                         result.add(link.domainElement);
444                 }
445                 else {
446                         for(Link<Domain,Range> link : modifiedRangeLinks)
447                                 if(link.domainModified)
448                                         result.add(link.domainElement);
449                 }
450                 return result;
451         }
452
453         @Override
454         public Collection<Range> getConflictingRangeElements() {
455                 ArrayList<Range> result = new ArrayList<Range>();
456                 if(modifiedDomainLinks.size() < modifiedRangeLinks.size()) {
457                         for(Link<Domain,Range> link : modifiedDomainLinks)
458                                 if(link.rangeModified)
459                                         result.add(link.rangeElement);
460                 }
461                 else {
462                         for(Link<Domain,Range> link : modifiedRangeLinks)
463                                 if(link.domainModified)
464                                         result.add(link.rangeElement);
465                 }
466                 return result;
467         }
468
469     @Override
470     public void dispose() {
471         disposed = true;
472     }
473     
474     public boolean isDisposed() {
475         return disposed;
476     }
477         
478 }