001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/io/datastore/sql/transaction/delete/FeatureGraph.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstraße 19
030: 53177 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042: ---------------------------------------------------------------------------*/
043: package org.deegree.io.datastore.sql.transaction.delete;
044:
045: import java.util.ArrayList;
046: import java.util.HashMap;
047: import java.util.HashSet;
048: import java.util.List;
049: import java.util.Map;
050: import java.util.Set;
051:
052: import org.deegree.framework.log.ILogger;
053: import org.deegree.framework.log.LoggerFactory;
054: import org.deegree.i18n.Messages;
055: import org.deegree.io.datastore.DatastoreException;
056: import org.deegree.io.datastore.FeatureId;
057: import org.deegree.io.datastore.schema.MappedFeaturePropertyType;
058: import org.deegree.io.datastore.sql.AbstractRequestHandler;
059: import org.deegree.io.datastore.sql.LockHandler;
060: import org.deegree.ogcwebservices.wfs.operation.transaction.Delete;
061:
062: /**
063: * Used to determine the structure of features and subfeatures that have to be deleted by a {@link Delete} operation.
064: * <p>
065: * When features are selected for deletion, all of their descendant subfeatures will be deleted as well, except for
066: * those features that have superfeatures which are not descendants of the features to be deleted.
067: *
068: * @see DeleteHandler
069: * @see FeatureNode
070: *
071: * @author <a href="mailto:schneider@lat-lon.de">Markus Schneider</a>
072: * @author last edited by: $Author: apoth $
073: *
074: * @version $Revision: 9342 $, $Date: 2007-12-27 04:32:57 -0800 (Thu, 27 Dec 2007) $
075: */
076: public class FeatureGraph {
077:
078: private static final ILogger LOG = LoggerFactory
079: .getLogger(FeatureGraph.class);
080:
081: private AbstractRequestHandler handler;
082:
083: private Set<FeatureId> rootFeatures = new HashSet<FeatureId>();
084:
085: private Map<FeatureId, FeatureNode> fidToNode = new HashMap<FeatureId, FeatureNode>();
086:
087: /**
088: * Creates a new <code>FeatureGraph</code> instance for the given root {@link FeatureId}s and the specified
089: * {@link DeleteHandler}.
090: *
091: * @param rootFids
092: * ids of the feature instances to be deleted
093: * @param handler
094: * associated <code>DeleteHandler</code>
095: * @throws DatastoreException
096: */
097: FeatureGraph(List<FeatureId> rootFids, DeleteHandler handler)
098: throws DatastoreException {
099: this .handler = handler;
100: for (FeatureId fid : rootFids) {
101: this .rootFeatures.add(fid);
102: addNode(fid);
103: }
104: markUndeletableFeatures();
105: }
106:
107: /**
108: * Creates a new <code>FeatureGraph</code> instance for the given root {@link FeatureId}s and the specified
109: * {@link LockHandler}.
110: *
111: * @param rootFids
112: * ids of the feature instances to be locked
113: * @param handler
114: * associated <code>LockHandler</code>
115: * @throws DatastoreException
116: */
117: public FeatureGraph(Set<FeatureId> rootFids, LockHandler handler)
118: throws DatastoreException {
119: this .handler = handler;
120: for (FeatureId fid : rootFids) {
121: this .rootFeatures.add(fid);
122: addNode(fid);
123: }
124: }
125:
126: /**
127: * Returns the {@link FeatureId}s of all features contained in the graph.
128: *
129: * @return the <code>FeatureId</code>s of all features contained in the graph
130: */
131: public Set<FeatureId> getAllFids() {
132: return this .fidToNode.keySet();
133: }
134:
135: /**
136: * Returns the {@link FeatureNode} that represents the feature with the given {@link FeatureId}.
137: *
138: * @param fid
139: * id of the feature to look up
140: * @return the corresponding <code>FeatureNode</code> if it exists in the graph, null otherwise
141: */
142: FeatureNode getNode(FeatureId fid) {
143: return fidToNode.get(fid);
144: }
145:
146: /**
147: * Returns the {@link FeatureNode}s that represent all root features that have been targeted for deletion.
148: *
149: * @return <code>FeatureNode</code> representing all root features
150: */
151: List<FeatureNode> getRootNodes() {
152: List<FeatureNode> rootNodes = new ArrayList<FeatureNode>(
153: this .rootFeatures.size());
154: for (FeatureId fid : rootFeatures) {
155: rootNodes.add(getNode(fid));
156: }
157: return rootNodes;
158: }
159:
160: /**
161: * Adds the specified feature (and it's descendants) (as {@link FeatureNode}s).
162: *
163: * @param fid
164: * the id of the feature to be added
165: * @throws DatastoreException
166: */
167: private void addNode(FeatureId fid) throws DatastoreException {
168:
169: if (this .fidToNode.get(fid) == null) {
170: // skip determination of super features if feature is not deletable anyway
171: Set<FeatureId> super Features = null;
172: if (fid.getFeatureType().isDeletable()) {
173: super Features = handler.determineSuperFeatures(fid);
174: } else {
175: LOG
176: .logDebug("Skipping super feature lookup for feature: "
177: + fid
178: + " -- feature type is not deletable anyway.");
179: super Features = new HashSet<FeatureId>();
180: super Features.add(fid);
181: }
182:
183: Map<MappedFeaturePropertyType, List<FeatureId>> subFeatures = handler
184: .determineSubFeatures(fid);
185: FeatureNode node = new FeatureNode(this , fid, subFeatures,
186: super Features);
187: this .fidToNode.put(fid, node);
188:
189: for (FeatureId subFid : node.getSubFeatureIds()) {
190: addNode(subFid);
191: }
192: }
193: }
194:
195: /**
196: * Marks all {@link FeatureNode}s in the graph that cannot be deleted, because they are descendants (subfeatures)
197: * of other undeletable {@link FeatureNode}s.
198: */
199: private void markUndeletableFeatures() {
200:
201: LOG.logDebug("Determining undeletable features.");
202:
203: int lastVetoCount = -1;
204: int vetoCount = 0;
205:
206: while (vetoCount != lastVetoCount) {
207: LOG.logDebug("vetoCount: " + vetoCount);
208: LOG.logDebug("lastVetoCount: " + lastVetoCount);
209: lastVetoCount = vetoCount;
210: vetoCount = 0;
211: for (FeatureNode node : this .fidToNode.values()) {
212: if (node.isDeletable()) {
213: boolean deletable = true;
214: if (!node.getFid().getFeatureType().isDeletable()) {
215: String msg = Messages.getMessage(
216: "DATASTORE_FEATURE_NOT_DELETABLE", node
217: .getFid().toString());
218: LOG.logInfo(msg);
219: deletable = false;
220: } else {
221: for (FeatureId super Fid : node
222: .getSuperFeatureIds()) {
223: FeatureNode super Node = getNode(super Fid);
224: if (super Node == null
225: || !super Node.isDeletable()) {
226: deletable = false;
227: break;
228: }
229: }
230: }
231: if (!deletable) {
232: node.markAsUndeletable();
233: vetoCount++;
234: }
235: } else {
236: vetoCount++;
237: }
238: }
239: }
240: LOG.logDebug("Delete vetos: " + lastVetoCount);
241: }
242:
243: @Override
244: public String toString() {
245: StringBuffer sb = new StringBuffer("FeatureGraph:\n");
246: for (FeatureId rootFid : this .rootFeatures) {
247: sb.append(this .fidToNode.get(rootFid).toString("",
248: new HashSet<FeatureNode>()));
249: }
250: return sb.toString();
251: }
252: }
|