1 /******************************************************************************* 2 * Copyright (c) 2003, 2016 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Rob Harrop - SpringSource Inc. (bug 247522) 14 *******************************************************************************/ 15 package org.eclipse.osgi.internal.resolver; 16 17 import java.util.*; 18 import org.eclipse.osgi.service.resolver.*; 19 20 /** 21 * This class is threadsafe. 22 * 23 */ 24 final class StateDeltaImpl implements StateDelta { 25 26 private final State state; 27 28 private final Map<BundleDescription, BundleDelta> changes = new HashMap<>(); 29 private ResolverHookException error; 30 StateDeltaImpl(State state)31 public StateDeltaImpl(State state) { 32 this.state = state; 33 } 34 getChanges()35 public BundleDelta[] getChanges() { 36 synchronized (this.changes) { 37 return changes.values().toArray(new BundleDelta[changes.size()]); 38 } 39 } 40 getChanges(int mask, boolean exact)41 public BundleDelta[] getChanges(int mask, boolean exact) { 42 synchronized (this.changes) { 43 List<BundleDelta> result = new ArrayList<>(); 44 for (Iterator<BundleDelta> changesIter = changes.values().iterator(); changesIter.hasNext();) { 45 BundleDelta change = changesIter.next(); 46 if (mask == change.getType() || (!exact && (change.getType() & mask) != 0)) 47 result.add(change); 48 } 49 return result.toArray(new BundleDelta[result.size()]); 50 } 51 } 52 getState()53 public State getState() { 54 return state; 55 } 56 getResovlerHookException()57 public ResolverHookException getResovlerHookException() { 58 return error; 59 } 60 setResolverHookException(ResolverHookException error)61 void setResolverHookException(ResolverHookException error) { 62 this.error = error; 63 } 64 recordBundleAdded(BundleDescriptionImpl added)65 void recordBundleAdded(BundleDescriptionImpl added) { 66 synchronized (this.changes) { 67 BundleDeltaImpl change = (BundleDeltaImpl) changes.get(added); 68 if (change == null) { 69 changes.put(added, new BundleDeltaImpl(added, BundleDelta.ADDED)); 70 return; 71 } 72 if (change.getType() == BundleDelta.REMOVED) { 73 changes.remove(added); 74 return; 75 } 76 int newType = change.getType(); 77 if ((newType & BundleDelta.REMOVED) != 0) 78 newType &= ~BundleDelta.REMOVED; 79 change.setType(newType | BundleDelta.ADDED); 80 change.setBundle(added); 81 } 82 } 83 recordBundleUpdated(BundleDescriptionImpl updated)84 void recordBundleUpdated(BundleDescriptionImpl updated) { 85 synchronized (this.changes) { 86 BundleDeltaImpl change = (BundleDeltaImpl) changes.get(updated); 87 if (change == null) { 88 changes.put(updated, new BundleDeltaImpl(updated, BundleDelta.UPDATED)); 89 return; 90 } 91 if ((change.getType() & (BundleDelta.ADDED | BundleDelta.REMOVED)) != 0) 92 return; 93 change.setType(change.getType() | BundleDelta.UPDATED); 94 change.setBundle(updated); 95 } 96 } 97 recordBundleRemoved(BundleDescriptionImpl removed)98 void recordBundleRemoved(BundleDescriptionImpl removed) { 99 synchronized (this.changes) { 100 BundleDeltaImpl change = (BundleDeltaImpl) changes.get(removed); 101 if (change == null) { 102 changes.put(removed, new BundleDeltaImpl(removed, BundleDelta.REMOVED)); 103 return; 104 } 105 if (change.getType() == BundleDelta.ADDED) { 106 changes.remove(removed); 107 return; 108 } 109 int newType = change.getType(); 110 if ((newType & BundleDelta.ADDED) != 0) 111 newType &= ~BundleDelta.ADDED; 112 change.setType(newType | BundleDelta.REMOVED); 113 } 114 } 115 recordBundleRemovalPending(BundleDescriptionImpl removed)116 void recordBundleRemovalPending(BundleDescriptionImpl removed) { 117 synchronized (this.changes) { 118 BundleDeltaImpl change = (BundleDeltaImpl) changes.get(removed); 119 if (change == null) { 120 changes.put(removed, new BundleDeltaImpl(removed, BundleDelta.REMOVAL_PENDING)); 121 return; 122 } 123 int newType = change.getType(); 124 if ((newType & BundleDelta.REMOVAL_COMPLETE) != 0) 125 newType &= ~BundleDelta.REMOVAL_COMPLETE; 126 change.setType(newType | BundleDelta.REMOVAL_PENDING); 127 } 128 } 129 recordBundleRemovalComplete(BundleDescriptionImpl removed)130 void recordBundleRemovalComplete(BundleDescriptionImpl removed) { 131 synchronized (this.changes) { 132 BundleDeltaImpl change = (BundleDeltaImpl) changes.get(removed); 133 if (change == null) { 134 changes.put(removed, new BundleDeltaImpl(removed, BundleDelta.REMOVAL_COMPLETE)); 135 return; 136 } 137 int newType = change.getType(); 138 if ((newType & BundleDelta.REMOVAL_PENDING) != 0) 139 newType &= ~BundleDelta.REMOVAL_PENDING; 140 change.setType(newType | BundleDelta.REMOVAL_COMPLETE); 141 } 142 } 143 recordBundleResolved(BundleDescriptionImpl resolved, boolean result)144 void recordBundleResolved(BundleDescriptionImpl resolved, boolean result) { 145 synchronized (this.changes) { 146 if (resolved.isResolved() == result) 147 return; // do not record anything if nothing has changed 148 BundleDeltaImpl change = (BundleDeltaImpl) changes.get(resolved); 149 int newType = result ? BundleDelta.RESOLVED : BundleDelta.UNRESOLVED; 150 if (change == null) { 151 change = new BundleDeltaImpl(resolved, newType); 152 changes.put(resolved, change); 153 return; 154 } 155 // new type will have only one of RESOLVED|UNRESOLVED bits set 156 newType = newType | (change.getType() & ~(BundleDelta.RESOLVED | BundleDelta.UNRESOLVED)); 157 change.setType(newType); 158 change.setBundle(resolved); 159 } 160 } 161 } 162