]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/util/History.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core extension / org / eclipse / jdt / internal / corext / util / History.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
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 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.corext.util;
12
13import java.io.File;
14import java.io.FileInputStream;
15import java.io.FileOutputStream;
16import java.io.IOException;
17import java.io.InputStreamReader;
18import java.io.OutputStream;
19import java.util.Collection;
20import java.util.Hashtable;
21import java.util.Iterator;
22import java.util.LinkedHashMap;
23import java.util.Map;
24import java.util.Set;
25
26import javax.xml.parsers.DocumentBuilder;
27import javax.xml.parsers.DocumentBuilderFactory;
28import javax.xml.parsers.ParserConfigurationException;
29import javax.xml.transform.OutputKeys;
30import javax.xml.transform.Transformer;
31import javax.xml.transform.TransformerException;
32import javax.xml.transform.TransformerFactory;
33import javax.xml.transform.TransformerFactoryConfigurationError;
34import javax.xml.transform.dom.DOMSource;
35import javax.xml.transform.stream.StreamResult;
36
37import org.xml.sax.InputSource;
38import org.xml.sax.SAXException;
39import org.xml.sax.helpers.DefaultHandler;
40
41import org.w3c.dom.Document;
42import org.w3c.dom.Element;
43import org.w3c.dom.Node;
44import org.w3c.dom.NodeList;
45
46import org.eclipse.core.runtime.CoreException;
47import org.eclipse.core.runtime.IPath;
48import org.eclipse.core.runtime.IStatus;
49
50import org.eclipse.jdt.internal.corext.CorextMessages;
51
52import org.eclipse.jdt.internal.ui.JavaPlugin;
53import org.eclipse.jdt.internal.ui.JavaUIException;
54import org.eclipse.jdt.internal.ui.JavaUIStatus;
55import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
56
57/**
58 * History stores a list of key, object pairs. The list is bounded at size
59 * MAX_HISTORY_SIZE. If the list exceeds this size the eldest element is removed
60 * from the list. An element can be added/renewed with a call to <code>accessed(Object)</code>.
61 *
62 * The history can be stored to/loaded from an xml file.
63 */
64public abstract class History {
65
66 private static final String DEFAULT_ROOT_NODE_NAME= "histroyRootNode"; //$NON-NLS-1$
67 private static final String DEFAULT_INFO_NODE_NAME= "infoNode"; //$NON-NLS-1$
68 private static final int MAX_HISTORY_SIZE= 60;
69
70 private static JavaUIException createException(Throwable t, String message) {
71 return new JavaUIException(JavaUIStatus.createError(IStatus.ERROR, message, t));
72 }
73
74 private final Map<Object, Object> fHistory;
75 private final Hashtable<Object, Integer> fPositions;
76 private final String fFileName;
77 private final String fRootNodeName;
78 private final String fInfoNodeName;
79
80 public History(String fileName, String rootNodeName, String infoNodeName) {
81 fHistory= new LinkedHashMap<Object, Object>(80, 0.75f, true) {
82 private static final long serialVersionUID= 1L;
83 @Override
84 protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
85 return size() > MAX_HISTORY_SIZE;
86 }
87 };
88 fFileName= fileName;
89 fRootNodeName= rootNodeName;
90 fInfoNodeName= infoNodeName;
91 fPositions= new Hashtable<Object, Integer>(MAX_HISTORY_SIZE);
92 }
93
94 public History(String fileName) {
95 this(fileName, DEFAULT_ROOT_NODE_NAME, DEFAULT_INFO_NODE_NAME);
96 }
97
98 public synchronized void accessed(Object object) {
99 fHistory.put(getKey(object), object);
100 rebuildPositions();
101 }
102
103 public synchronized boolean contains(Object object) {
104 return fHistory.containsKey(getKey(object));
105 }
106
107 public synchronized boolean containsKey(Object key) {
108 return fHistory.containsKey(key);
109 }
110
111 public synchronized boolean isEmpty() {
112 return fHistory.isEmpty();
113 }
114
115 public synchronized Object remove(Object object) {
116 Object removed= fHistory.remove(getKey(object));
117 rebuildPositions();
118 return removed;
119 }
120
121 public synchronized Object removeKey(Object key) {
122 Object removed= fHistory.remove(key);
123 rebuildPositions();
124 return removed;
125 }
126
127 /**
128 * Normalized position in history of object denoted by key.
129 * The position is a value between zero and one where zero
130 * means not contained in history and one means newest element
131 * in history. The lower the value the older the element.
132 *
133 * @param key The key of the object to inspect
134 * @return value in [0.0, 1.0] the lower the older the element
135 */
136 public synchronized float getNormalizedPosition(Object key) {
137 if (!containsKey(key))
138 return 0.0f;
139
140 int pos= fPositions.get(key).intValue() + 1;
141
142 //containsKey(key) implies fHistory.size()>0
143 return (float)pos / (float)fHistory.size();
144 }
145
146 /**
147 * Absolute position of object denoted by key in the
148 * history or -1 if !containsKey(key). The higher the
149 * newer.
150 *
151 * @param key The key of the object to inspect
152 * @return value between 0 and MAX_HISTORY_SIZE - 1, or -1
153 */
154 public synchronized int getPosition(Object key) {
155 if (!containsKey(key))
156 return -1;
157
158 return fPositions.get(key).intValue();
159 }
160
161 public synchronized void load() {
162 IPath stateLocation= JavaPlugin.getDefault().getStateLocation().append(fFileName);
163 File file= stateLocation.toFile();
164 if (file.exists()) {
165 InputStreamReader reader= null;
166 try {
167 reader = new InputStreamReader(new FileInputStream(file), "utf-8");//$NON-NLS-1$
168 load(new InputSource(reader));
169 } catch (IOException e) {
170 JavaPlugin.log(e);
171 } catch (CoreException e) {
172 JavaPlugin.log(e);
173 } finally {
174 try {
175 if (reader != null)
176 reader.close();
177 } catch (IOException e) {
178 JavaPlugin.log(e);
179 }
180 }
181 }
182 }
183
184 public synchronized void save() {
185 IPath stateLocation= JavaPlugin.getDefault().getStateLocation().append(fFileName);
186 File file= stateLocation.toFile();
187 OutputStream out= null;
188 try {
189 out= new FileOutputStream(file);
190 save(out);
191 } catch (IOException e) {
192 JavaPlugin.log(e);
193 } catch (CoreException e) {
194 JavaPlugin.log(e);
195 } catch (TransformerFactoryConfigurationError e) {
196 // The XML library can be misconficgured (e.g. via
197 // -Djava.endorsed.dirs=C:\notExisting\xerces-2_7_1)
198 JavaPlugin.log(e);
199 } finally {
200 try {
201 if (out != null) {
202 out.close();
203 }
204 } catch (IOException e) {
205 JavaPlugin.log(e);
206 }
207 }
208 }
209
210 protected Set<Object> getKeys() {
211 return fHistory.keySet();
212 }
213
214 protected Collection<Object> getValues() {
215 return fHistory.values();
216 }
217
218 /**
219 * Store <code>Object</code> in <code>Element</code>
220 *
221 * @param object The object to store
222 * @param element The Element to store to
223 */
224 protected abstract void setAttributes(Object object, Element element);
225
226 /**
227 * Return a new instance of an Object given <code>element</code>
228 *
229 * @param element The element containing required information to create the Object
230 * @return return a new instance of an Object given <code>element</code>
231 */
232 protected abstract Object createFromElement(Element element);
233
234 /**
235 * Get key for object
236 *
237 * @param object The object to calculate a key for, not null
238 * @return The key for object, not null
239 */
240 protected abstract Object getKey(Object object);
241
242 private void rebuildPositions() {
243 fPositions.clear();
244 Collection<Object> values= fHistory.values();
245 int pos=0;
246 for (Iterator<Object> iter= values.iterator(); iter.hasNext();) {
247 Object element= iter.next();
248 fPositions.put(getKey(element), new Integer(pos));
249 pos++;
250 }
251 }
252
253 private void load(InputSource inputSource) throws CoreException {
254 Element root;
255 try {
256 DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
257 parser.setErrorHandler(new DefaultHandler());
258 root = parser.parse(inputSource).getDocumentElement();
259 } catch (SAXException e) {
260 throw createException(e, Messages.format(CorextMessages.History_error_read, BasicElementLabels.getResourceName(fFileName)));
261 } catch (ParserConfigurationException e) {
262 throw createException(e, Messages.format(CorextMessages.History_error_read, BasicElementLabels.getResourceName(fFileName)));
263 } catch (IOException e) {
264 throw createException(e, Messages.format(CorextMessages.History_error_read, BasicElementLabels.getResourceName(fFileName)));
265 }
266
267 if (root == null) return;
268 if (!root.getNodeName().equalsIgnoreCase(fRootNodeName)) {
269 return;
270 }
271 NodeList list= root.getChildNodes();
272 int length= list.getLength();
273 for (int i= 0; i < length; ++i) {
274 Node node= list.item(i);
275 if (node.getNodeType() == Node.ELEMENT_NODE) {
276 Element type= (Element) node;
277 if (type.getNodeName().equalsIgnoreCase(fInfoNodeName)) {
278 Object object= createFromElement(type);
279 if (object != null) {
280 fHistory.put(getKey(object), object);
281 }
282 }
283 }
284 }
285 rebuildPositions();
286 }
287
288 private void save(OutputStream stream) throws CoreException {
289 try {
290 DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
291 DocumentBuilder builder= factory.newDocumentBuilder();
292 Document document= builder.newDocument();
293
294 Element rootElement = document.createElement(fRootNodeName);
295 document.appendChild(rootElement);
296
297 Iterator<Object> values= getValues().iterator();
298 while (values.hasNext()) {
299 Object object= values.next();
300 Element element= document.createElement(fInfoNodeName);
301 setAttributes(object, element);
302 rootElement.appendChild(element);
303 }
304
305 Transformer transformer=TransformerFactory.newInstance().newTransformer();
306 transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
307 transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$
308 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
309 DOMSource source = new DOMSource(document);
310 StreamResult result = new StreamResult(stream);
311
312 transformer.transform(source, result);
313 } catch (TransformerException e) {
314 throw createException(e, Messages.format(CorextMessages.History_error_serialize, BasicElementLabels.getResourceName(fFileName)));
315 } catch (ParserConfigurationException e) {
316 throw createException(e, Messages.format(CorextMessages.History_error_serialize, BasicElementLabels.getResourceName(fFileName)));
317 }
318 }
319
320}