[927] | 1 | // Copyright 2012 Georg-August-Universität Göttingen, Germany |
---|
| 2 | // |
---|
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
---|
| 4 | // you may not use this file except in compliance with the License. |
---|
| 5 | // You may obtain a copy of the License at |
---|
| 6 | // |
---|
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
---|
| 8 | // |
---|
| 9 | // Unless required by applicable law or agreed to in writing, software |
---|
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
---|
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
| 12 | // See the License for the specific language governing permissions and |
---|
| 13 | // limitations under the License. |
---|
| 14 | |
---|
[922] | 15 | package de.ugoe.cs.autoquest.plugin.jfc; |
---|
[787] | 16 | |
---|
[833] | 17 | import java.io.BufferedOutputStream; |
---|
[787] | 18 | import java.io.File; |
---|
| 19 | import java.io.FileInputStream; |
---|
| 20 | import java.io.FileNotFoundException; |
---|
| 21 | import java.io.FileOutputStream; |
---|
| 22 | import java.io.IOException; |
---|
| 23 | import java.io.InputStreamReader; |
---|
| 24 | import java.io.PrintStream; |
---|
| 25 | import java.io.UnsupportedEncodingException; |
---|
| 26 | import java.util.ArrayList; |
---|
[840] | 27 | import java.util.Collections; |
---|
[833] | 28 | import java.util.HashMap; |
---|
[787] | 29 | import java.util.List; |
---|
[833] | 30 | import java.util.Map; |
---|
[787] | 31 | |
---|
| 32 | import javax.xml.parsers.ParserConfigurationException; |
---|
| 33 | import javax.xml.parsers.SAXParser; |
---|
| 34 | import javax.xml.parsers.SAXParserFactory; |
---|
| 35 | |
---|
| 36 | import org.xml.sax.Attributes; |
---|
| 37 | import org.xml.sax.InputSource; |
---|
| 38 | import org.xml.sax.SAXException; |
---|
| 39 | import org.xml.sax.SAXParseException; |
---|
| 40 | import org.xml.sax.helpers.DefaultHandler; |
---|
| 41 | |
---|
[795] | 42 | import de.ugoe.cs.util.StringTools; |
---|
[787] | 43 | import de.ugoe.cs.util.console.Console; |
---|
| 44 | |
---|
| 45 | /** |
---|
| 46 | * <p> |
---|
[829] | 47 | * corrects older JFC log files which sometimes do not contain correct source specifications for |
---|
| 48 | * events. It parses the file and adds component specifications to the sources, that do not have |
---|
| 49 | * them. For each invalid source it checks, if there is another source with the same |
---|
| 50 | * <code>toString</code> parameter but a complete list of components. If one is found, it is reused |
---|
| 51 | * as source for the event with the wrong source. If none is found, a new component list is |
---|
| 52 | * generated. This contains as parent components the components of the source of the previous event. |
---|
| 53 | * The leaf component is parsed from the <code>toString</code> parameter that is provided with the |
---|
[787] | 54 | * source specifications. The resulting leaf nodes are not fully correct. They may pretend to |
---|
[829] | 55 | * be equal although they are not. Furthermore they may resist at a position in the GUI tree where |
---|
| 56 | * they are not in reality. But more correctness is not achievable based on the |
---|
[787] | 57 | * <code>toString</code> parameter. |
---|
| 58 | * </p> |
---|
| 59 | * |
---|
| 60 | * @version $Revision: $ $Date: 05.09.2012$ |
---|
| 61 | * @author 2012, last modified by $Author: pharms$ |
---|
| 62 | */ |
---|
| 63 | public class JFCTraceCorrector extends DefaultHandler { |
---|
| 64 | |
---|
| 65 | /** |
---|
| 66 | * <p> |
---|
| 67 | * the file to write the result into |
---|
| 68 | * </p> |
---|
| 69 | */ |
---|
| 70 | private PrintStream outFile; |
---|
| 71 | |
---|
| 72 | /** |
---|
| 73 | * <p> |
---|
| 74 | * the currently parsed event |
---|
| 75 | * </p> |
---|
| 76 | */ |
---|
| 77 | private Event currentEvent; |
---|
| 78 | |
---|
| 79 | /** |
---|
| 80 | * <p> |
---|
| 81 | * the currently parsed source of the currently parsed event |
---|
| 82 | * </p> |
---|
| 83 | */ |
---|
| 84 | private Source currentSource; |
---|
| 85 | |
---|
| 86 | /** |
---|
| 87 | * <p> |
---|
[833] | 88 | * the list of all sources parsed in a file identified through their <code>toString</code> |
---|
| 89 | * representation |
---|
[787] | 90 | * </p> |
---|
| 91 | */ |
---|
[833] | 92 | private Map<String, List<Source>> allSources = new HashMap<String, List<Source>>(); |
---|
[787] | 93 | |
---|
| 94 | /** |
---|
| 95 | * <p> |
---|
| 96 | * the currently parsed component of the currently parsed source of the currently parsed event |
---|
| 97 | * </p> |
---|
| 98 | */ |
---|
| 99 | private Component currentComponent; |
---|
| 100 | |
---|
| 101 | /** |
---|
| 102 | * <p> |
---|
| 103 | * the currently parsed session |
---|
| 104 | * </p> |
---|
| 105 | */ |
---|
| 106 | private Session currentSession; |
---|
| 107 | |
---|
| 108 | /** |
---|
| 109 | * <p> |
---|
| 110 | * corrects the given file and returns the name of the file into which the result was written |
---|
| 111 | * </p> |
---|
| 112 | * |
---|
| 113 | * @param filename the name of the file to be corrected |
---|
| 114 | * |
---|
| 115 | * @return the name of the file with the corrected logfile |
---|
| 116 | * |
---|
| 117 | * @throws IllegalArgumentException if the filename is null |
---|
| 118 | */ |
---|
| 119 | public String correctFile(String filename) throws IllegalArgumentException { |
---|
| 120 | if (filename == null) { |
---|
| 121 | throw new IllegalArgumentException("filename must not be null"); |
---|
| 122 | } |
---|
| 123 | |
---|
| 124 | return correctFile(new File(filename)).getAbsolutePath(); |
---|
| 125 | } |
---|
| 126 | |
---|
| 127 | /** |
---|
| 128 | * <p> |
---|
| 129 | * corrects the given file, stores the result in the second provided file and returns the |
---|
| 130 | * name of the file into which the result was written |
---|
| 131 | * </p> |
---|
| 132 | * |
---|
| 133 | * @param filename the name of the file to be corrected |
---|
| 134 | * @param resultFile the name of the file into which the corrected log shall be written |
---|
| 135 | * |
---|
| 136 | * @return the name of the file with the corrected logfile |
---|
| 137 | * |
---|
| 138 | * @throws IllegalArgumentException if the filename or resultFile is null |
---|
| 139 | */ |
---|
| 140 | public String correctFile(String filename, String resultFile) throws IllegalArgumentException { |
---|
| 141 | if ((filename == null) | (resultFile == null)) { |
---|
| 142 | throw new IllegalArgumentException("filename and resultFile must not be null"); |
---|
| 143 | } |
---|
| 144 | |
---|
| 145 | return correctFile(new File(filename), new File(resultFile)).getAbsolutePath(); |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | /** |
---|
| 149 | * <p> |
---|
| 150 | * corrects the given file and returns the file into which the result was written. The name |
---|
| 151 | * of the resulting file is contains the suffix "_corrected" before the dot. |
---|
| 152 | * </p> |
---|
| 153 | * |
---|
| 154 | * @param file the file to be corrected |
---|
| 155 | * |
---|
| 156 | * @return the file containing the corrected logfile |
---|
| 157 | * |
---|
| 158 | * @throws IllegalArgumentException if the file is null |
---|
| 159 | */ |
---|
| 160 | public File correctFile(File file) throws IllegalArgumentException { |
---|
| 161 | if (file == null) { |
---|
| 162 | throw new IllegalArgumentException("file must not be null"); |
---|
| 163 | } |
---|
| 164 | |
---|
| 165 | int index = file.getName().lastIndexOf('.'); |
---|
| 166 | String fileName = |
---|
| 167 | file.getName().substring(0, index) + "_corrected" + file.getName().substring(index); |
---|
| 168 | |
---|
| 169 | File resultFile = new File(file.getParentFile(), fileName); |
---|
| 170 | |
---|
| 171 | return correctFile(file, resultFile); |
---|
| 172 | } |
---|
| 173 | |
---|
| 174 | /** |
---|
| 175 | * <p> |
---|
| 176 | * corrects the given file, stores the result in the second provided file and returns the |
---|
| 177 | * file into which the result was written |
---|
| 178 | * </p> |
---|
| 179 | * |
---|
| 180 | * @param file the file to be corrected |
---|
| 181 | * @param resultFile the file into which the corrected log shall be written |
---|
| 182 | * |
---|
| 183 | * @return the file with the corrected logfile |
---|
| 184 | * |
---|
| 185 | * @throws IllegalArgumentException if the file or resultFile is null or if they are equal |
---|
| 186 | */ |
---|
| 187 | public File correctFile(File file, File resultFile) throws IllegalArgumentException { |
---|
| 188 | if ((file == null) || (resultFile == null)) { |
---|
| 189 | throw new IllegalArgumentException("file and result file must not be null"); |
---|
| 190 | } |
---|
| 191 | |
---|
| 192 | if (file.getAbsolutePath().equals(resultFile.getAbsolutePath())) { |
---|
| 193 | throw new IllegalArgumentException("file and result file must not be equal"); |
---|
| 194 | } |
---|
| 195 | |
---|
| 196 | try { |
---|
[1079] | 197 | outFile = new PrintStream |
---|
| 198 | (new BufferedOutputStream(new FileOutputStream(resultFile)), false, "UTF-8"); |
---|
[787] | 199 | outFile.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); |
---|
| 200 | } |
---|
| 201 | catch (FileNotFoundException e1) { |
---|
| 202 | throw new IllegalArgumentException("could not create a corrected file name " + |
---|
| 203 | resultFile + " next to " + file); |
---|
| 204 | } |
---|
[1079] | 205 | catch (UnsupportedEncodingException e) { |
---|
| 206 | throw new IllegalArgumentException("this host does not support UTF-8 encoding"); |
---|
| 207 | } |
---|
[787] | 208 | |
---|
| 209 | |
---|
| 210 | SAXParserFactory spf = SAXParserFactory.newInstance(); |
---|
| 211 | spf.setValidating(true); |
---|
| 212 | |
---|
| 213 | SAXParser saxParser = null; |
---|
| 214 | InputSource inputSource = null; |
---|
| 215 | try { |
---|
| 216 | saxParser = spf.newSAXParser(); |
---|
| 217 | inputSource = |
---|
| 218 | new InputSource(new InputStreamReader(new FileInputStream(file), "UTF-8")); |
---|
| 219 | } |
---|
| 220 | catch (UnsupportedEncodingException e) { |
---|
| 221 | Console.printerr("Error parsing file + " + file.getName()); |
---|
| 222 | Console.logException(e); |
---|
| 223 | return null; |
---|
| 224 | } |
---|
| 225 | catch (ParserConfigurationException e) { |
---|
| 226 | Console.printerr("Error parsing file + " + file.getName()); |
---|
| 227 | Console.logException(e); |
---|
| 228 | return null; |
---|
| 229 | } |
---|
| 230 | catch (SAXException e) { |
---|
| 231 | Console.printerr("Error parsing file + " + file.getName()); |
---|
| 232 | Console.logException(e); |
---|
| 233 | return null; |
---|
| 234 | } |
---|
| 235 | catch (FileNotFoundException e) { |
---|
| 236 | Console.printerr("Error parsing file + " + file.getName()); |
---|
| 237 | Console.logException(e); |
---|
| 238 | return null; |
---|
| 239 | } |
---|
| 240 | if (inputSource != null) { |
---|
| 241 | inputSource.setSystemId("file://" + file.getAbsolutePath()); |
---|
| 242 | try { |
---|
| 243 | if (saxParser == null) { |
---|
| 244 | throw new RuntimeException("SAXParser creation failed"); |
---|
| 245 | } |
---|
| 246 | saxParser.parse(inputSource, this); |
---|
| 247 | } |
---|
| 248 | catch (SAXParseException e) { |
---|
| 249 | Console.printerrln("Failure parsing file in line " + e.getLineNumber() + |
---|
| 250 | ", column " + e.getColumnNumber() + "."); |
---|
| 251 | Console.logException(e); |
---|
| 252 | return null; |
---|
| 253 | } |
---|
| 254 | catch (SAXException e) { |
---|
| 255 | Console.printerr("Error parsing file + " + file.getName()); |
---|
| 256 | Console.logException(e); |
---|
| 257 | return null; |
---|
| 258 | } |
---|
| 259 | catch (IOException e) { |
---|
| 260 | Console.printerr("Error parsing file + " + file.getName()); |
---|
| 261 | Console.logException(e); |
---|
| 262 | return null; |
---|
| 263 | } |
---|
| 264 | } |
---|
| 265 | |
---|
| 266 | if (outFile != null) { |
---|
| 267 | outFile.close(); |
---|
| 268 | } |
---|
| 269 | |
---|
| 270 | return resultFile; |
---|
| 271 | } |
---|
| 272 | |
---|
| 273 | /* |
---|
| 274 | * (non-Javadoc) |
---|
| 275 | * |
---|
| 276 | * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, |
---|
| 277 | * java.lang.String, org.xml.sax.Attributes) |
---|
| 278 | */ |
---|
| 279 | public void startElement(String uri, String localName, String qName, Attributes atts) |
---|
| 280 | throws SAXException |
---|
| 281 | { |
---|
| 282 | if (qName.equals("sessions")) { |
---|
[840] | 283 | if (currentSession != null) { |
---|
| 284 | throw new SAXException("nested sessions are not allowed"); |
---|
| 285 | } |
---|
| 286 | |
---|
| 287 | currentSession = new Session("sessions"); |
---|
[787] | 288 | } |
---|
| 289 | else if (qName.equals("newsession")) { |
---|
| 290 | if (currentSession != null) { |
---|
| 291 | currentSession.dump(outFile); |
---|
| 292 | } |
---|
| 293 | |
---|
[840] | 294 | currentSession = new Session("newsession"); |
---|
[787] | 295 | } |
---|
| 296 | else if (qName.equals("event")) { |
---|
[840] | 297 | if (currentEvent != null) { |
---|
| 298 | throw new SAXException("nested events are not allowed"); |
---|
| 299 | } |
---|
| 300 | |
---|
| 301 | currentEvent = new Event(atts.getValue("id")); |
---|
[787] | 302 | } |
---|
| 303 | else if (qName.equals("source")) { |
---|
[840] | 304 | if (currentSource != null) { |
---|
| 305 | throw new SAXException("nested sources are not allowed"); |
---|
| 306 | } |
---|
| 307 | |
---|
[787] | 308 | currentSource = new Source(); |
---|
| 309 | } |
---|
| 310 | else if (qName.equals("component")) { |
---|
[840] | 311 | if (currentComponent != null) { |
---|
| 312 | throw new SAXException("nested components are not allowed"); |
---|
| 313 | } |
---|
| 314 | |
---|
[787] | 315 | currentComponent = new Component(); |
---|
| 316 | } |
---|
| 317 | else if (qName.equals("param")) { |
---|
| 318 | if (currentComponent != null) { |
---|
[840] | 319 | currentComponent.addParameter(atts.getValue("name"), atts.getValue("value")); |
---|
[787] | 320 | } |
---|
| 321 | else if (currentSource != null) { |
---|
[840] | 322 | currentSource.addParameter(atts.getValue("name"), atts.getValue("value")); |
---|
[787] | 323 | } |
---|
| 324 | else if (currentEvent != null) { |
---|
[840] | 325 | currentEvent.addParameter(atts.getValue("name"), atts.getValue("value")); |
---|
[787] | 326 | } |
---|
| 327 | else { |
---|
| 328 | throw new SAXException("parameter occurred at an unexpected place"); |
---|
| 329 | } |
---|
| 330 | } |
---|
| 331 | else { |
---|
| 332 | throw new SAXException("unexpected tag " + qName); |
---|
| 333 | } |
---|
| 334 | } |
---|
| 335 | |
---|
| 336 | /* |
---|
| 337 | * (non-Javadoc) |
---|
| 338 | * |
---|
| 339 | * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, |
---|
| 340 | * java.lang.String) |
---|
| 341 | */ |
---|
| 342 | @Override |
---|
| 343 | public void endElement(String uri, String localName, String qName) throws SAXException { |
---|
[840] | 344 | // we do not have to check, if the current objects are null, as the Parser itself will |
---|
| 345 | // throw an exception, if there is a closing tag for a non existent opening tag. But |
---|
| 346 | // with a correct opening tag, the member variables will not be null (see startElement()) |
---|
[787] | 347 | if (qName.equals("sessions")) { |
---|
[829] | 348 | correctSources(currentSession); |
---|
[787] | 349 | |
---|
| 350 | currentSession.dump(outFile); |
---|
| 351 | currentSession = null; |
---|
[834] | 352 | allSources.clear(); |
---|
[787] | 353 | } |
---|
| 354 | else if (qName.equals("newsession")) { |
---|
[829] | 355 | correctSources(currentSession); |
---|
[787] | 356 | |
---|
| 357 | currentSession.dump(outFile); |
---|
| 358 | currentSession = null; |
---|
[834] | 359 | allSources.clear(); |
---|
[787] | 360 | } |
---|
| 361 | else if (qName.equals("event")) { |
---|
[840] | 362 | currentSession.addEvent(currentEvent); |
---|
[787] | 363 | currentEvent = null; |
---|
| 364 | } |
---|
| 365 | else if (qName.equals("source")) { |
---|
[840] | 366 | currentEvent.setSource(getUniqueSource(currentSource)); |
---|
[787] | 367 | currentSource = null; |
---|
| 368 | } |
---|
| 369 | else if (qName.equals("component")) { |
---|
[840] | 370 | currentSource.addComponent(currentComponent); |
---|
[787] | 371 | currentComponent = null; |
---|
| 372 | } |
---|
| 373 | else if (!qName.equals("param")) { |
---|
| 374 | throw new SAXException("unexpected closing tag " + qName); |
---|
| 375 | } |
---|
| 376 | |
---|
| 377 | } |
---|
| 378 | |
---|
| 379 | /** |
---|
[829] | 380 | * <p> |
---|
[840] | 381 | * returns a source object, that is equal to the provided one but that is unique throughout |
---|
| 382 | * the parsing process. The method may return the provided source, if this is the first |
---|
| 383 | * occurrence of this source. This method is needed to reduce the amount of source |
---|
| 384 | * representations that are instantiated during parsing log files. |
---|
[829] | 385 | * </p> |
---|
| 386 | * |
---|
[840] | 387 | * @param source the source to search for a unique representation |
---|
| 388 | * |
---|
| 389 | * @return the unique representation of the source |
---|
[787] | 390 | */ |
---|
[834] | 391 | private Source getUniqueSource(Source source) { |
---|
[840] | 392 | Source existingSource = null; |
---|
[833] | 393 | |
---|
[840] | 394 | List<Source> candidates = allSources.get(source.getToStringValue()); |
---|
[833] | 395 | |
---|
[840] | 396 | if (candidates != null) { |
---|
| 397 | for (Source candidate : candidates) { |
---|
| 398 | if (candidate.equals(source)) { |
---|
| 399 | existingSource = candidate; |
---|
| 400 | break; |
---|
| 401 | } |
---|
[834] | 402 | } |
---|
[840] | 403 | } |
---|
| 404 | |
---|
| 405 | if (existingSource == null) { |
---|
| 406 | if (candidates == null) { |
---|
| 407 | candidates = new ArrayList<Source>(); |
---|
| 408 | allSources.put(source.getToStringValue(), candidates); |
---|
| 409 | } |
---|
[834] | 410 | |
---|
[840] | 411 | candidates.add(source); |
---|
[834] | 412 | existingSource = source; |
---|
[833] | 413 | } |
---|
| 414 | |
---|
[834] | 415 | return existingSource; |
---|
[829] | 416 | } |
---|
[787] | 417 | |
---|
| 418 | /** |
---|
[829] | 419 | * <p> |
---|
[833] | 420 | * convenience method to find a source based on its <code>toString</code> parameter value. |
---|
| 421 | * The method only returns sources, which match the provided <code>toString</code> |
---|
[840] | 422 | * representation and which have a valid list of components (size greater 0). |
---|
[833] | 423 | * </p> |
---|
| 424 | * |
---|
| 425 | * @param toStringValue the value of the <code>toString</code> parameter the source to find |
---|
| 426 | * must have |
---|
| 427 | * |
---|
| 428 | * @return the source matching the parameter and having a valid list of components or null if |
---|
| 429 | * none is found |
---|
| 430 | */ |
---|
[840] | 431 | private Source findValidSource(String toStringValue) { |
---|
[833] | 432 | Source existingSource = null; |
---|
| 433 | |
---|
| 434 | List<Source> candidates = allSources.get(toStringValue); |
---|
| 435 | |
---|
| 436 | if (candidates != null) { |
---|
| 437 | for (Source candidate : candidates) { |
---|
[840] | 438 | if ((candidate.getComponents() != null) && (candidate.getComponents().size() > 0)) |
---|
[833] | 439 | { |
---|
| 440 | existingSource = candidate; |
---|
[834] | 441 | break; |
---|
[833] | 442 | } |
---|
| 443 | } |
---|
| 444 | } |
---|
| 445 | |
---|
| 446 | return existingSource; |
---|
| 447 | } |
---|
| 448 | |
---|
| 449 | /** |
---|
| 450 | * <p> |
---|
[829] | 451 | * corrects all wrong sources in the events of the session. For each wrong resource, the |
---|
| 452 | * {@link #correctEventSource(Event, Source)} method is called. |
---|
| 453 | * </p> |
---|
[787] | 454 | * |
---|
[829] | 455 | * @param session the session of which the events shall be corrected |
---|
[787] | 456 | */ |
---|
[829] | 457 | private void correctSources(Session session) { |
---|
| 458 | Source previousSource = null; |
---|
[840] | 459 | for (Event event : session.getEvents()) { |
---|
| 460 | if ((event.getSource() == null) || (event.getSource().getComponents() == null) || |
---|
| 461 | (event.getSource().getComponents().size() == 0)) |
---|
[829] | 462 | { |
---|
| 463 | correctEventSource(event, previousSource); |
---|
[787] | 464 | } |
---|
[829] | 465 | |
---|
[840] | 466 | previousSource = event.getSource(); |
---|
[787] | 467 | } |
---|
[829] | 468 | } |
---|
[787] | 469 | |
---|
| 470 | /** |
---|
[829] | 471 | * <p> |
---|
| 472 | * corrects the source of an event. It first searches for a correct source with an equal |
---|
| 473 | * <code>toString</code> parameter. If there is any, this is reused. Otherwise it creates a |
---|
| 474 | * new correct source. For this, it copies all parameters of the source of the provided previous |
---|
| 475 | * event if they are not included in the source already. Furthermore, it adds all components |
---|
| 476 | * of the source of the previous event. At last, it adds a further component based on the |
---|
| 477 | * information found in the <code>toString</code> parameter of the source. |
---|
| 478 | * </p> |
---|
[787] | 479 | * |
---|
[829] | 480 | * @param event the event of which the source must be corrected |
---|
| 481 | * @param previousSource the source of the previous event to be potentially reused partially |
---|
[787] | 482 | */ |
---|
[829] | 483 | private void correctEventSource(Event event, Source previousSource) { |
---|
| 484 | Source existingSource = null; |
---|
| 485 | |
---|
[840] | 486 | if ((event.getSource() != null) && (event.getSource().getToStringValue() != null)) { |
---|
| 487 | existingSource = findValidSource(event.getSource().getToStringValue()); |
---|
[787] | 488 | } |
---|
| 489 | |
---|
[829] | 490 | if (existingSource != null) { |
---|
[840] | 491 | event.setSource(existingSource); |
---|
[829] | 492 | } |
---|
| 493 | else { |
---|
| 494 | if (previousSource != null) { |
---|
[840] | 495 | for (Parameter parameterOfPreviousSource : previousSource.getParameters()) { |
---|
[829] | 496 | boolean foundParameter = false; |
---|
[840] | 497 | for (Parameter parameter : event.getSource().getParameters()) { |
---|
| 498 | if (parameter.getName().equals(parameterOfPreviousSource.getName())) { |
---|
[829] | 499 | foundParameter = true; |
---|
| 500 | break; |
---|
| 501 | } |
---|
| 502 | } |
---|
| 503 | |
---|
| 504 | if (!foundParameter) { |
---|
[840] | 505 | event.getSource().addParameter(parameterOfPreviousSource); |
---|
[829] | 506 | } |
---|
| 507 | } |
---|
| 508 | |
---|
[840] | 509 | for (Component component : previousSource.getComponents()) { |
---|
[829] | 510 | if (!(component instanceof ComponentFromToString)) { |
---|
[840] | 511 | event.getSource().addComponent(component); |
---|
[829] | 512 | } |
---|
| 513 | } |
---|
[787] | 514 | } |
---|
[829] | 515 | |
---|
[840] | 516 | event.getSource().addComponent |
---|
| 517 | (getComponentFromToString(event.getSource().getToStringValue())); |
---|
[787] | 518 | } |
---|
[829] | 519 | } |
---|
[787] | 520 | |
---|
| 521 | /** |
---|
| 522 | * <p> |
---|
[829] | 523 | * determines a component based on the <code>toString</code> parameter of a source. |
---|
[787] | 524 | * For this, it parses the parameter value and tries to determine several infos such as the |
---|
| 525 | * type and the name of it. The resulting components are not always distinguishable. This is, |
---|
| 526 | * because the <code>toString</code> parameter does not contain sufficient information for |
---|
| 527 | * correct identification. |
---|
| 528 | * </p> |
---|
| 529 | * |
---|
[829] | 530 | * @param toStringValue the <code>toString</code> parameter of a source |
---|
[787] | 531 | * |
---|
| 532 | * @return the component parsed from the <code>toString</code> parameter |
---|
| 533 | */ |
---|
[829] | 534 | private Component getComponentFromToString(String toStringValue) { |
---|
[787] | 535 | ComponentFromToString component = new ComponentFromToString(); |
---|
| 536 | |
---|
| 537 | // search for the beginning of the parameters section. Up to this position we find the class |
---|
| 538 | int start = toStringValue.indexOf('['); |
---|
| 539 | String clazz = toStringValue.substring(0, start); |
---|
| 540 | |
---|
| 541 | // the first parameters are x and y coordinate as well as the size. The size is one |
---|
| 542 | // parameter, where with and height are separated with an 'x' |
---|
| 543 | start = toStringValue.indexOf(',', start) + 1; |
---|
| 544 | int end = toStringValue.indexOf(',', start); |
---|
| 545 | |
---|
[840] | 546 | component.setX(Integer.parseInt(toStringValue.substring(start, end))); |
---|
[787] | 547 | |
---|
| 548 | start = end + 1; |
---|
| 549 | end = toStringValue.indexOf(',', start); |
---|
| 550 | |
---|
[840] | 551 | component.setY(Integer.parseInt(toStringValue.substring(start, end))); |
---|
[787] | 552 | |
---|
| 553 | start = end + 1; |
---|
| 554 | end = toStringValue.indexOf('x', start); |
---|
| 555 | |
---|
[840] | 556 | component.setWidth(Integer.parseInt(toStringValue.substring(start, end))); |
---|
[787] | 557 | |
---|
| 558 | start = end + 1; |
---|
| 559 | end = toStringValue.indexOf(',', start); |
---|
| 560 | |
---|
[840] | 561 | component.setHeight(Integer.parseInt(toStringValue.substring(start, end))); |
---|
[787] | 562 | |
---|
| 563 | // no start parsing the rest of the parameters and extract those having a key and a |
---|
| 564 | // value and whose key is text, defaultIcon, or an alignment |
---|
| 565 | int intermediate; |
---|
| 566 | start = end + 1; |
---|
| 567 | |
---|
| 568 | String title = null; |
---|
| 569 | String icon = null; |
---|
| 570 | String alignment = null; |
---|
| 571 | |
---|
| 572 | do { |
---|
| 573 | end = toStringValue.indexOf(',', start); |
---|
| 574 | intermediate = toStringValue.indexOf('[', start); |
---|
| 575 | |
---|
| 576 | if ((intermediate >= 0) && (intermediate < end)) { |
---|
| 577 | // the value of the parameter itself contains brackets. So try to determine the |
---|
| 578 | // real end of the parameter |
---|
| 579 | end = toStringValue.indexOf(']', intermediate); |
---|
| 580 | end = toStringValue.indexOf(',', end); |
---|
| 581 | } |
---|
| 582 | |
---|
| 583 | if (end < 0) { |
---|
| 584 | //we reached the end of the stream. So the the end to the "end" |
---|
| 585 | end = toStringValue.lastIndexOf(']'); |
---|
| 586 | } |
---|
| 587 | |
---|
| 588 | intermediate = toStringValue.indexOf('=', start); |
---|
| 589 | |
---|
| 590 | if ((intermediate >= 0) && (intermediate < end)) { |
---|
| 591 | // this is a key value pair, so store the the parameter |
---|
| 592 | String key = toStringValue.substring(start, intermediate); |
---|
| 593 | String value = toStringValue.substring(intermediate + 1, end); |
---|
| 594 | |
---|
| 595 | if ("text".equals(key)) { |
---|
| 596 | title = value; |
---|
| 597 | } |
---|
| 598 | else if ("defaultIcon".equals(key)) { |
---|
| 599 | icon = value; |
---|
| 600 | } |
---|
| 601 | else if ("alignmentX".equals(key) || "alignmentY".equals(key)) { |
---|
| 602 | if (alignment == null) { |
---|
| 603 | alignment = value; |
---|
| 604 | } |
---|
| 605 | else { |
---|
| 606 | alignment += "/" + value; |
---|
| 607 | } |
---|
| 608 | } |
---|
| 609 | } |
---|
| 610 | /*else { |
---|
| 611 | // this is a simple value, for now simply ignore it |
---|
| 612 | String key = toStringValue.substring(start, end); |
---|
| 613 | if (!"invalid".equals(key)) { |
---|
| 614 | componentHash += key.hashCode(); |
---|
| 615 | component.params.add(new String[] { key, "true" }); |
---|
| 616 | } |
---|
| 617 | }*/ |
---|
| 618 | |
---|
| 619 | start = end + 1; |
---|
| 620 | } |
---|
| 621 | while (start < toStringValue.lastIndexOf(']')); |
---|
| 622 | |
---|
| 623 | // finish the component specification by setting the parameters |
---|
[792] | 624 | if ((title == null) || "".equals(title) || "null".equals(title)) { |
---|
| 625 | if ((icon == null) || "".equals(icon) || "null".equals(icon)) { |
---|
[787] | 626 | title = clazz.substring(clazz.lastIndexOf('.') + 1) + "("; |
---|
| 627 | |
---|
| 628 | // to be able to distinguish some elements, that usually have no name and icon, try |
---|
| 629 | // to include some of their specific identifying information in their name. |
---|
| 630 | if ("org.tigris.gef.presentation.FigTextEditor".equals(clazz) || |
---|
| 631 | "org.argouml.core.propertypanels.ui.UMLTextField".equals(clazz)) |
---|
| 632 | { |
---|
| 633 | title += "height " + component.height + ", "; |
---|
| 634 | } |
---|
| 635 | else if ("org.argouml.core.propertypanels.ui.UMLLinkedList".equals(clazz) || |
---|
| 636 | "org.argouml.core.propertypanels.ui.LabelledComponent".equals(clazz)) |
---|
| 637 | { |
---|
[840] | 638 | title += "position " + component.getX() + "/" + component.getY() + ", "; |
---|
[787] | 639 | } |
---|
| 640 | |
---|
| 641 | title += "alignment " + alignment + ")"; |
---|
| 642 | } |
---|
| 643 | else { |
---|
[843] | 644 | // to be able to distinguish some elements, that usually have no name but an icon, |
---|
| 645 | // try to include some of their specific identifying information in their name. |
---|
| 646 | if ("org.tigris.toolbar.toolbutton.PopupToolBoxButton".equals(clazz)) |
---|
| 647 | { |
---|
| 648 | icon = icon.substring(0, icon.lastIndexOf('@')); |
---|
| 649 | title = clazz.substring(clazz.lastIndexOf('.') + 1) + "(position " + |
---|
| 650 | component.getX() + ")"; |
---|
| 651 | } |
---|
| 652 | else { |
---|
| 653 | title = icon; |
---|
| 654 | } |
---|
[787] | 655 | } |
---|
| 656 | } |
---|
| 657 | |
---|
[840] | 658 | component.addParameter("title", title); |
---|
| 659 | component.addParameter("class", clazz); |
---|
| 660 | component.addParameter("icon", ((icon == null) ? "" : icon)); |
---|
| 661 | component.addParameter("index", "-1"); |
---|
[787] | 662 | |
---|
| 663 | int hashCode = clazz.hashCode() + title.hashCode(); |
---|
| 664 | |
---|
| 665 | if (hashCode < 0) { |
---|
| 666 | hashCode = -hashCode; |
---|
| 667 | } |
---|
| 668 | |
---|
[840] | 669 | component.addParameter("hash", Integer.toString(hashCode, 16)); |
---|
[787] | 670 | |
---|
| 671 | return component; |
---|
| 672 | } |
---|
| 673 | |
---|
| 674 | /** |
---|
| 675 | * <p> |
---|
| 676 | * used to dump a list of parameters to the provided print stream |
---|
| 677 | * </p> |
---|
| 678 | */ |
---|
[1079] | 679 | private static void dumpParams(PrintStream out, List<Parameter> params, String indent) { |
---|
[840] | 680 | for (Parameter param : params) { |
---|
[787] | 681 | out.print(indent); |
---|
| 682 | out.print("<param name=\""); |
---|
[840] | 683 | out.print(StringTools.xmlEntityReplacement(param.getName())); |
---|
[787] | 684 | out.print("\" value=\""); |
---|
[840] | 685 | out.print(StringTools.xmlEntityReplacement(param.getValue())); |
---|
[787] | 686 | out.println("\" />"); |
---|
| 687 | } |
---|
| 688 | |
---|
| 689 | } |
---|
| 690 | |
---|
| 691 | /** |
---|
| 692 | * <p> |
---|
[840] | 693 | * check if two parameter lists are equal. Thea are equal if the contain the same parameters |
---|
| 694 | * ignoring their order. |
---|
| 695 | * </p> |
---|
| 696 | * |
---|
| 697 | * @param params1 the first parameter list to be compared |
---|
| 698 | * @param params2 the second parameter list to be compared |
---|
| 699 | * |
---|
| 700 | * @return true if both lists contain the same parameters, false else. |
---|
| 701 | */ |
---|
[1079] | 702 | private static boolean parametersEqual(List<Parameter> params1, List<Parameter> params2) { |
---|
[840] | 703 | if (params1 == null) { |
---|
| 704 | return params2 == null; |
---|
| 705 | } |
---|
| 706 | |
---|
| 707 | if (params2 == null) { |
---|
| 708 | return false; |
---|
| 709 | } |
---|
| 710 | |
---|
| 711 | if (params1.size() != params2.size()) { |
---|
| 712 | return false; |
---|
| 713 | } |
---|
| 714 | |
---|
| 715 | boolean found; |
---|
| 716 | for (Parameter param1 : params1) { |
---|
| 717 | found = false; |
---|
| 718 | |
---|
| 719 | for (Parameter param2 : params2) { |
---|
| 720 | if (param1.equals(param2)) { |
---|
| 721 | found = true; |
---|
| 722 | break; |
---|
| 723 | } |
---|
| 724 | } |
---|
| 725 | |
---|
| 726 | if (!found) { |
---|
| 727 | return false; |
---|
| 728 | } |
---|
| 729 | } |
---|
| 730 | |
---|
| 731 | return true; |
---|
| 732 | } |
---|
| 733 | |
---|
| 734 | |
---|
| 735 | /** |
---|
| 736 | * <p> |
---|
[787] | 737 | * used to carry all events of a session and to dump it to the output file |
---|
| 738 | * </p> |
---|
| 739 | */ |
---|
[1079] | 740 | private static class Session { |
---|
[840] | 741 | |
---|
| 742 | /** */ |
---|
[787] | 743 | private String type; |
---|
[840] | 744 | |
---|
| 745 | /** */ |
---|
[787] | 746 | private List<Event> events = new ArrayList<Event>(); |
---|
| 747 | |
---|
[840] | 748 | /** |
---|
| 749 | * |
---|
| 750 | */ |
---|
| 751 | private Session(String type) { |
---|
| 752 | if (type == null) { |
---|
| 753 | throw new IllegalArgumentException("type must not be null"); |
---|
| 754 | } |
---|
| 755 | |
---|
| 756 | this.type = type; |
---|
| 757 | } |
---|
| 758 | |
---|
| 759 | /** |
---|
| 760 | * |
---|
| 761 | */ |
---|
| 762 | private void addEvent(Event event) { |
---|
| 763 | if (event == null) { |
---|
| 764 | throw new IllegalArgumentException("event must not be null"); |
---|
| 765 | } |
---|
| 766 | |
---|
| 767 | events.add(event); |
---|
| 768 | } |
---|
| 769 | |
---|
| 770 | /** |
---|
| 771 | * @return the events |
---|
| 772 | */ |
---|
| 773 | private List<Event> getEvents() { |
---|
| 774 | return Collections.unmodifiableList(events); |
---|
| 775 | } |
---|
| 776 | |
---|
| 777 | /** |
---|
| 778 | * |
---|
| 779 | */ |
---|
| 780 | private void dump(PrintStream out) { |
---|
| 781 | if (out == null) { |
---|
| 782 | throw new IllegalArgumentException("out must not be null"); |
---|
| 783 | } |
---|
| 784 | |
---|
[787] | 785 | out.print("<"); |
---|
| 786 | out.print(type); |
---|
| 787 | out.println(">"); |
---|
| 788 | |
---|
| 789 | for (Event event : events) { |
---|
| 790 | event.dump(out); |
---|
| 791 | } |
---|
| 792 | |
---|
| 793 | out.print("</"); |
---|
| 794 | out.print(type); |
---|
| 795 | out.println(">"); |
---|
| 796 | } |
---|
| 797 | } |
---|
| 798 | |
---|
| 799 | /** |
---|
| 800 | * <p> |
---|
| 801 | * used to carry all information about an event and to dump it to the output file |
---|
| 802 | * </p> |
---|
| 803 | */ |
---|
[1079] | 804 | private static class Event { |
---|
[840] | 805 | |
---|
| 806 | /** */ |
---|
[787] | 807 | private String id; |
---|
[840] | 808 | |
---|
| 809 | /** */ |
---|
| 810 | private List<Parameter> params = new ArrayList<Parameter>(); |
---|
| 811 | |
---|
| 812 | /** */ |
---|
[787] | 813 | private Source source; |
---|
| 814 | |
---|
[840] | 815 | /** |
---|
| 816 | * |
---|
| 817 | */ |
---|
| 818 | private Event(String id) { |
---|
| 819 | if (id == null) { |
---|
| 820 | throw new IllegalArgumentException("id must not be null"); |
---|
| 821 | } |
---|
| 822 | |
---|
| 823 | this.id = id; |
---|
| 824 | } |
---|
| 825 | |
---|
| 826 | /** |
---|
| 827 | * @param source the source to set |
---|
| 828 | */ |
---|
| 829 | private void setSource(Source source) { |
---|
| 830 | this.source = source; |
---|
| 831 | } |
---|
| 832 | |
---|
| 833 | /** |
---|
| 834 | * @return the source |
---|
| 835 | */ |
---|
| 836 | private Source getSource() { |
---|
| 837 | return source; |
---|
| 838 | } |
---|
| 839 | |
---|
| 840 | /** |
---|
| 841 | * |
---|
| 842 | */ |
---|
| 843 | private void addParameter(String name, String value) { |
---|
| 844 | if (name == null) { |
---|
| 845 | throw new IllegalArgumentException("name must not be null"); |
---|
| 846 | } |
---|
| 847 | |
---|
| 848 | if (value == null) { |
---|
| 849 | throw new IllegalArgumentException("value must not be null"); |
---|
| 850 | } |
---|
| 851 | |
---|
| 852 | params.add(new Parameter(name, value)); |
---|
| 853 | } |
---|
| 854 | |
---|
| 855 | /** |
---|
| 856 | * |
---|
| 857 | */ |
---|
[787] | 858 | private void dump(PrintStream out) { |
---|
[840] | 859 | if (out == null) { |
---|
| 860 | throw new IllegalArgumentException("out must not be null"); |
---|
| 861 | } |
---|
| 862 | |
---|
[787] | 863 | out.print("<event id=\""); |
---|
[795] | 864 | out.print(StringTools.xmlEntityReplacement(id)); |
---|
[787] | 865 | out.println("\">"); |
---|
| 866 | |
---|
| 867 | dumpParams(out, params, " "); |
---|
| 868 | source.dump(out); |
---|
| 869 | |
---|
| 870 | out.println("</event>"); |
---|
| 871 | } |
---|
| 872 | } |
---|
| 873 | |
---|
| 874 | /** |
---|
| 875 | * <p> |
---|
| 876 | * used to carry all information about a source of an event and to dump it to the output file |
---|
| 877 | * </p> |
---|
| 878 | */ |
---|
[1079] | 879 | private static class Source { |
---|
[840] | 880 | |
---|
| 881 | /** */ |
---|
| 882 | private List<Parameter> params = new ArrayList<Parameter>(); |
---|
| 883 | |
---|
| 884 | /** */ |
---|
[787] | 885 | private List<Component> components = new ArrayList<Component>(); |
---|
[840] | 886 | |
---|
| 887 | /** */ |
---|
| 888 | private String toStringValue = null; |
---|
[787] | 889 | |
---|
[840] | 890 | /** |
---|
| 891 | * |
---|
| 892 | */ |
---|
| 893 | private String getToStringValue() { |
---|
| 894 | if (toStringValue == null) { |
---|
| 895 | for (Parameter param : params) { |
---|
| 896 | if (("toString".equals(param.getName())) && |
---|
| 897 | (param.getValue() != null) && (!"".equals(param.getValue()))) |
---|
| 898 | { |
---|
| 899 | toStringValue = param.getValue(); |
---|
| 900 | break; |
---|
| 901 | } |
---|
| 902 | } |
---|
| 903 | } |
---|
| 904 | |
---|
| 905 | return toStringValue; |
---|
| 906 | } |
---|
| 907 | |
---|
| 908 | /** |
---|
| 909 | * |
---|
| 910 | */ |
---|
| 911 | private void addParameter(String name, String value) { |
---|
| 912 | if (name == null) { |
---|
| 913 | throw new IllegalArgumentException("name must not be null"); |
---|
| 914 | } |
---|
| 915 | |
---|
| 916 | if (value == null) { |
---|
| 917 | throw new IllegalArgumentException("value must not be null"); |
---|
| 918 | } |
---|
| 919 | |
---|
| 920 | params.add(new Parameter(name, value)); |
---|
| 921 | } |
---|
| 922 | |
---|
| 923 | /** |
---|
| 924 | * |
---|
| 925 | */ |
---|
| 926 | private void addParameter(Parameter parameter) { |
---|
| 927 | if (parameter == null) { |
---|
| 928 | throw new IllegalArgumentException("parameter must not be null"); |
---|
| 929 | } |
---|
| 930 | |
---|
| 931 | params.add(parameter); |
---|
| 932 | } |
---|
| 933 | |
---|
| 934 | /** |
---|
| 935 | * @return the params |
---|
| 936 | */ |
---|
| 937 | private List<Parameter> getParameters() { |
---|
| 938 | return Collections.unmodifiableList(params); |
---|
| 939 | } |
---|
| 940 | |
---|
| 941 | /** |
---|
| 942 | * |
---|
| 943 | */ |
---|
| 944 | private void addComponent(Component component) { |
---|
| 945 | if (component == null) { |
---|
| 946 | throw new IllegalArgumentException("component must not be null"); |
---|
| 947 | } |
---|
| 948 | |
---|
| 949 | components.add(component); |
---|
| 950 | } |
---|
| 951 | |
---|
| 952 | /** |
---|
| 953 | * @return the components |
---|
| 954 | */ |
---|
| 955 | private List<Component> getComponents() { |
---|
| 956 | return Collections.unmodifiableList(components); |
---|
| 957 | } |
---|
| 958 | |
---|
| 959 | /** |
---|
| 960 | * |
---|
| 961 | */ |
---|
[787] | 962 | private void dump(PrintStream out) { |
---|
[840] | 963 | if (out == null) { |
---|
| 964 | throw new IllegalArgumentException("out must not be null"); |
---|
| 965 | } |
---|
| 966 | |
---|
[787] | 967 | out.println(" <source>"); |
---|
| 968 | |
---|
| 969 | dumpParams(out, params, " "); |
---|
| 970 | |
---|
| 971 | for (Component component : components) { |
---|
| 972 | component.dump(out); |
---|
| 973 | } |
---|
| 974 | |
---|
| 975 | out.println(" </source>"); |
---|
| 976 | } |
---|
[840] | 977 | |
---|
| 978 | /* (non-Javadoc) |
---|
| 979 | * @see java.lang.Object#equals(java.lang.Object) |
---|
| 980 | */ |
---|
| 981 | @Override |
---|
| 982 | public boolean equals(Object obj) { |
---|
| 983 | if (this == obj) { |
---|
| 984 | return true; |
---|
| 985 | } |
---|
| 986 | |
---|
| 987 | if (obj instanceof Source) { |
---|
| 988 | Source other = (Source) obj; |
---|
| 989 | |
---|
[1079] | 990 | if (getToStringValue() != null ? |
---|
| 991 | !getToStringValue().equals(other.getToStringValue()) : |
---|
| 992 | other.getToStringValue() != null) |
---|
[840] | 993 | { |
---|
| 994 | return false; |
---|
| 995 | } |
---|
| 996 | |
---|
| 997 | if (!parametersEqual(params, other.params)) { |
---|
| 998 | return false; |
---|
| 999 | } |
---|
| 1000 | |
---|
| 1001 | if (components == null) { |
---|
| 1002 | return other.components == null; |
---|
| 1003 | } |
---|
| 1004 | |
---|
| 1005 | if (other.components == null) { |
---|
| 1006 | return false; |
---|
| 1007 | } |
---|
| 1008 | |
---|
| 1009 | if (components.size() != other.components.size()) { |
---|
| 1010 | return false; |
---|
| 1011 | } |
---|
| 1012 | |
---|
| 1013 | for (int i = 0; i < components.size(); i++) { |
---|
| 1014 | if (!components.get(i).equals(other.components.get(i))) { |
---|
| 1015 | return false; |
---|
| 1016 | } |
---|
| 1017 | } |
---|
| 1018 | |
---|
| 1019 | return true; |
---|
| 1020 | } |
---|
| 1021 | |
---|
| 1022 | return false; |
---|
| 1023 | } |
---|
| 1024 | |
---|
| 1025 | /* (non-Javadoc) |
---|
| 1026 | * @see java.lang.Object#hashCode() |
---|
| 1027 | */ |
---|
| 1028 | @Override |
---|
| 1029 | public int hashCode() { |
---|
| 1030 | String str = getToStringValue(); |
---|
| 1031 | |
---|
| 1032 | if (str != null) { |
---|
| 1033 | return str.hashCode(); |
---|
| 1034 | } |
---|
| 1035 | else { |
---|
| 1036 | // ensure that all incomplete sources provide the same hashcode |
---|
| 1037 | return 0; |
---|
| 1038 | } |
---|
| 1039 | } |
---|
| 1040 | |
---|
[787] | 1041 | } |
---|
| 1042 | |
---|
| 1043 | /** |
---|
| 1044 | * <p> |
---|
| 1045 | * used to carry all information about a component of a source and to dump it to the output file |
---|
| 1046 | * </p> |
---|
| 1047 | */ |
---|
[1079] | 1048 | private static class Component { |
---|
[787] | 1049 | |
---|
[840] | 1050 | /** */ |
---|
| 1051 | private List<Parameter> params = new ArrayList<Parameter>(); |
---|
| 1052 | |
---|
| 1053 | /** |
---|
| 1054 | * |
---|
| 1055 | */ |
---|
| 1056 | protected void addParameter(String name, String value) { |
---|
| 1057 | if (name == null) { |
---|
| 1058 | throw new IllegalArgumentException("name must not be null"); |
---|
| 1059 | } |
---|
| 1060 | |
---|
| 1061 | if (value == null) { |
---|
| 1062 | throw new IllegalArgumentException("value must not be null"); |
---|
| 1063 | } |
---|
| 1064 | |
---|
| 1065 | params.add(new Parameter(name, value)); |
---|
| 1066 | } |
---|
| 1067 | |
---|
| 1068 | /** |
---|
| 1069 | * @return the params |
---|
| 1070 | */ |
---|
| 1071 | private List<Parameter> getParameters() { |
---|
| 1072 | return Collections.unmodifiableList(params); |
---|
| 1073 | } |
---|
| 1074 | |
---|
| 1075 | /** |
---|
| 1076 | * |
---|
| 1077 | */ |
---|
[787] | 1078 | protected void dump(PrintStream out) { |
---|
[840] | 1079 | if (out == null) { |
---|
| 1080 | throw new IllegalArgumentException("out must not be null"); |
---|
| 1081 | } |
---|
| 1082 | |
---|
[787] | 1083 | out.println(" <component>"); |
---|
| 1084 | dumpParams(out, params, " "); |
---|
| 1085 | out.println(" </component>"); |
---|
| 1086 | } |
---|
| 1087 | |
---|
[840] | 1088 | /** |
---|
| 1089 | * |
---|
| 1090 | */ |
---|
| 1091 | public boolean equals(Object obj) { |
---|
| 1092 | if (this == obj) { |
---|
[787] | 1093 | return true; |
---|
| 1094 | } |
---|
| 1095 | |
---|
[840] | 1096 | if (obj instanceof Component) { |
---|
| 1097 | return parametersEqual(params, ((Component) obj).params); |
---|
[787] | 1098 | } |
---|
[840] | 1099 | else { |
---|
| 1100 | return false; |
---|
[787] | 1101 | } |
---|
| 1102 | } |
---|
[840] | 1103 | |
---|
| 1104 | /* (non-Javadoc) |
---|
| 1105 | * @see java.lang.Object#hashCode() |
---|
| 1106 | */ |
---|
| 1107 | @Override |
---|
| 1108 | public int hashCode() { |
---|
| 1109 | // all components with an equally sized parameter list can be equal. This does not |
---|
| 1110 | // work, if not all component parameters are set yet. But we do not use components |
---|
| 1111 | // in a hash map so we provide an easy implementation |
---|
| 1112 | return params.size(); |
---|
| 1113 | } |
---|
[787] | 1114 | } |
---|
| 1115 | |
---|
| 1116 | /** |
---|
| 1117 | * <p> |
---|
| 1118 | * represents a specific component, which was read from the toString parameter of a source |
---|
| 1119 | * </p> |
---|
| 1120 | */ |
---|
[1079] | 1121 | private static class ComponentFromToString extends Component { |
---|
[840] | 1122 | |
---|
| 1123 | /** */ |
---|
[787] | 1124 | private int x; |
---|
[840] | 1125 | |
---|
| 1126 | /** */ |
---|
[787] | 1127 | private int y; |
---|
[840] | 1128 | |
---|
| 1129 | /** */ |
---|
[787] | 1130 | private int width; |
---|
[840] | 1131 | |
---|
| 1132 | /** */ |
---|
[787] | 1133 | private int height; |
---|
| 1134 | |
---|
[840] | 1135 | /** |
---|
| 1136 | * @param x the x to set |
---|
| 1137 | */ |
---|
| 1138 | private void setX(int x) { |
---|
| 1139 | this.x = x; |
---|
| 1140 | } |
---|
| 1141 | |
---|
| 1142 | /** |
---|
| 1143 | * @return the x |
---|
| 1144 | */ |
---|
| 1145 | private int getX() { |
---|
| 1146 | return x; |
---|
| 1147 | } |
---|
| 1148 | |
---|
| 1149 | /** |
---|
| 1150 | * @param y the y to set |
---|
| 1151 | */ |
---|
| 1152 | private void setY(int y) { |
---|
| 1153 | this.y = y; |
---|
| 1154 | } |
---|
| 1155 | |
---|
| 1156 | /** |
---|
| 1157 | * @return the y |
---|
| 1158 | */ |
---|
| 1159 | private int getY() { |
---|
| 1160 | return y; |
---|
| 1161 | } |
---|
| 1162 | |
---|
| 1163 | /** |
---|
| 1164 | * @param width the width to set |
---|
| 1165 | */ |
---|
| 1166 | private void setWidth(int width) { |
---|
| 1167 | this.width = width; |
---|
| 1168 | } |
---|
| 1169 | |
---|
| 1170 | /** |
---|
| 1171 | * @param height the height to set |
---|
| 1172 | */ |
---|
| 1173 | private void setHeight(int height) { |
---|
| 1174 | this.height = height; |
---|
| 1175 | } |
---|
| 1176 | |
---|
| 1177 | /** |
---|
| 1178 | * |
---|
| 1179 | */ |
---|
[787] | 1180 | @Override |
---|
| 1181 | protected void dump(PrintStream out) { |
---|
[840] | 1182 | if (out == null) { |
---|
| 1183 | throw new IllegalArgumentException("out must not be null"); |
---|
| 1184 | } |
---|
| 1185 | |
---|
[787] | 1186 | out.println(" <component>"); |
---|
| 1187 | |
---|
| 1188 | out.print(" "); |
---|
| 1189 | out.print("<param name=\"x\" value=\""); |
---|
| 1190 | out.print(x); |
---|
| 1191 | out.println("\" />"); |
---|
| 1192 | |
---|
| 1193 | out.print(" "); |
---|
| 1194 | out.print("<param name=\"y\" value=\""); |
---|
| 1195 | out.print(y); |
---|
| 1196 | out.println("\" />"); |
---|
| 1197 | |
---|
| 1198 | out.print(" "); |
---|
| 1199 | out.print("<param name=\"width\" value=\""); |
---|
| 1200 | out.print(width); |
---|
| 1201 | out.println("\" />"); |
---|
| 1202 | |
---|
| 1203 | out.print(" "); |
---|
| 1204 | out.print("<param name=\"height\" value=\""); |
---|
| 1205 | out.print(height); |
---|
| 1206 | out.println("\" />"); |
---|
| 1207 | |
---|
[840] | 1208 | dumpParams(out, super.getParameters(), " "); |
---|
[787] | 1209 | out.println(" </component>"); |
---|
| 1210 | } |
---|
| 1211 | |
---|
[840] | 1212 | /** |
---|
| 1213 | * |
---|
| 1214 | */ |
---|
| 1215 | public boolean equals(Object obj) { |
---|
| 1216 | if (!super.equals(obj)) { |
---|
| 1217 | return false; |
---|
[787] | 1218 | } |
---|
| 1219 | |
---|
[840] | 1220 | if (obj instanceof ComponentFromToString) { |
---|
| 1221 | ComponentFromToString other = (ComponentFromToString) obj; |
---|
| 1222 | return (x == other.x) && (y == other.y) && |
---|
| 1223 | (width == other.width) && (height == other.height); |
---|
[787] | 1224 | } |
---|
[840] | 1225 | else { |
---|
| 1226 | return false; |
---|
| 1227 | } |
---|
| 1228 | } |
---|
| 1229 | |
---|
| 1230 | /* (non-Javadoc) |
---|
| 1231 | * @see java.lang.Object#hashCode() |
---|
| 1232 | */ |
---|
| 1233 | @Override |
---|
| 1234 | public int hashCode() { |
---|
| 1235 | return super.hashCode() + x + y + width + height; |
---|
| 1236 | } |
---|
| 1237 | } |
---|
| 1238 | |
---|
| 1239 | /** |
---|
| 1240 | * <p> |
---|
| 1241 | * used to carry all information about a parameter being a key and a value |
---|
| 1242 | * </p> |
---|
| 1243 | */ |
---|
[1079] | 1244 | private static class Parameter { |
---|
[840] | 1245 | |
---|
| 1246 | /** */ |
---|
| 1247 | private String name; |
---|
| 1248 | |
---|
| 1249 | /** */ |
---|
| 1250 | private String value; |
---|
| 1251 | |
---|
| 1252 | /** |
---|
| 1253 | * |
---|
| 1254 | */ |
---|
| 1255 | private Parameter(String name, String value) { |
---|
| 1256 | if (name == null) { |
---|
| 1257 | throw new IllegalArgumentException("name must not be null"); |
---|
| 1258 | } |
---|
[787] | 1259 | |
---|
[840] | 1260 | if (value == null) { |
---|
| 1261 | throw new IllegalArgumentException("value must not be null"); |
---|
| 1262 | } |
---|
[787] | 1263 | |
---|
[840] | 1264 | this.name = name; |
---|
| 1265 | this.value = value; |
---|
| 1266 | } |
---|
| 1267 | |
---|
| 1268 | /** |
---|
| 1269 | * @return the name |
---|
| 1270 | */ |
---|
| 1271 | private String getName() { |
---|
| 1272 | return name; |
---|
| 1273 | } |
---|
| 1274 | |
---|
| 1275 | /** |
---|
| 1276 | * @return the value |
---|
| 1277 | */ |
---|
| 1278 | private String getValue() { |
---|
| 1279 | return value; |
---|
| 1280 | } |
---|
| 1281 | |
---|
| 1282 | /* (non-Javadoc) |
---|
| 1283 | * @see java.lang.Object#equals(java.lang.Object) |
---|
| 1284 | */ |
---|
| 1285 | @Override |
---|
| 1286 | public boolean equals(Object obj) { |
---|
| 1287 | if (obj instanceof Parameter) { |
---|
| 1288 | return |
---|
| 1289 | (name.equals(((Parameter) obj).name) && value.equals(((Parameter) obj).value)); |
---|
[787] | 1290 | } |
---|
[840] | 1291 | else { |
---|
| 1292 | return false; |
---|
| 1293 | } |
---|
| 1294 | } |
---|
| 1295 | |
---|
| 1296 | /* (non-Javadoc) |
---|
| 1297 | * @see java.lang.Object#hashCode() |
---|
| 1298 | */ |
---|
| 1299 | @Override |
---|
| 1300 | public int hashCode() { |
---|
| 1301 | return name.hashCode() + value.hashCode(); |
---|
| 1302 | } |
---|
| 1303 | |
---|
| 1304 | |
---|
[787] | 1305 | } |
---|
[840] | 1306 | |
---|
[787] | 1307 | } |
---|