svn commit: r16688 - trunk/src/argouml-app: src/org/argouml/persistence tests/org/argouml/persistence
Tom Morris <[email protected]>
| Newsgroups | gmane.comp.lang.uml.argouml.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: tfmorris
Date: 2009-01-23 13:11:04-0800
New Revision: 16688
Modified:
trunk/src/argouml-app/src/org/argouml/persistence/ProfileConfigurationFilePersister.java
trunk/src/argouml-app/tests/org/argouml/persistence/TestProfileConfigurationFilePersister.java
Log:
RESOLVED - issue 5656: Switch profile parsing to SAXParser based implementation. Add tests.
http://argouml.tigris.org/issues/show_bug.cgi?id=5656
Modified: trunk/src/argouml-app/src/org/argouml/persistence/ProfileConfigurationFilePersister.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/persistence/ProfileConfigurationFilePersister.java?view=diff&pathrev=16688&r1=16687&r2=16688
==============================================================================
--- trunk/src/argouml-app/src/org/argouml/persistence/ProfileConfigurationFilePersister.java (original)
+++ trunk/src/argouml-app/src/org/argouml/persistence/ProfileConfigurationFilePersister.java 2009-01-23 13:11:04-0800
@@ -1,5 +1,5 @@
// $Id$
-// Copyright (c) 2007-2008 The Regents of the University of California. All
+// Copyright (c) 2007-2009 The Regents of the University of California. All
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
@@ -24,12 +24,10 @@
package org.argouml.persistence;
-import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
@@ -38,7 +36,6 @@
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
@@ -55,6 +52,8 @@
import org.argouml.profile.ProfileFacade;
import org.argouml.profile.ProfileManager;
import org.argouml.profile.UserDefinedProfile;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
/**
* Persister for project's profile configuration.
@@ -79,39 +78,16 @@
public void load(Project project, InputStream inputStream)
throws OpenException {
try {
- BufferedReader br = new BufferedReader(new InputStreamReader(
- inputStream, Argo.getEncoding()));
-
- String line = null;
- while (true) {
- line = br.readLine();
- if (line.trim().equals("<profile>")) {
- break;
- }
+ ProfileConfigurationParser parser =
+ new ProfileConfigurationParser();
+ parser.parse(new InputSource(inputStream));
+ Collection<Profile> profiles = parser.getProfiles();
+
+ Collection<String> unresolved = parser.getUnresolvedFilenames();
+ if (!unresolved.isEmpty()) {
+ profiles.addAll(loadUnresolved(unresolved));
}
- Collection<Profile> profiles = new ArrayList<Profile>();
- while (true) {
- line = br.readLine().trim();
- if (line.equals("</profile>")) {
- break;
- }
-
- Profile profile = null;
- if (line.equals("<userDefined>")) {
- profile = handleUserDefinedProfile(br);
- // consumes the </userDefined>
- br.readLine();
- } else if (line.equals("<plugin>")) {
- profile = handlePluginProfile(br);
- // consumes closing tag
- br.readLine();
- }
-
- if (profile != null) {
- profiles.add(profile);
- }
- }
ProfileConfiguration pc = new ProfileConfiguration(project,
profiles);
project.setProfileConfiguration(pc);
@@ -123,65 +99,28 @@
}
}
- private static Profile handlePluginProfile(BufferedReader br)
- throws IOException, OpenException {
- Profile profile;
- String profileIdentifier = br.readLine().trim();
- profile = ProfileFacade.getManager().lookForRegisteredProfile(
- profileIdentifier);
- if (profile == null) {
-
- // for compatibility with older format
- profile = ProfileFacade.getManager().getProfileForClass(
- profileIdentifier);
-
- if (profile == null) {
- throw new OpenException("Plugin profile \"" + profileIdentifier
- + "\" is not available in installation.", null);
- }
- }
- return profile;
- }
-
- private static Profile handleUserDefinedProfile(BufferedReader br)
- throws IOException, OpenException {
- String line;
- Profile profile;
- line = br.readLine().trim();
- String fileName = line.substring(line.indexOf(">") + 1,
- line.indexOf("</")).trim();
-
- // consumes the <model> tag
- br.readLine();
- StringBuffer xmi = new StringBuffer();
-
- while (true) {
- line = br.readLine();
- if (line == null || line.contains("</model>")) {
- break;
- }
- xmi.append(line + "\n");
- }
+ /**
+ * Use XMI as a fall back alternative when the file for the user defined
+ * profile isn't found by the profile manager.
+ * <p>
+ * TODO: work in progress, see issue 5039
+ *
+ * @param unresolved collection of unresolved filenames from the parser
+ * @return collection of resolved profiles
+ */
+ private Collection<Profile> loadUnresolved(Collection<String> unresolved) {
+ Collection<Profile> profiles = new ArrayList<Profile>();
ProfileManager profileManager = ProfileFacade.getManager();
- profile = getMatchingUserDefinedProfile(fileName,
- profileManager);
- if (profile == null) {
- throw new OpenException(
- "User defined profile \"" + fileName
- + "\" isn't available in the current configuration.",
- null);
- // Use XMI as a fall back alternative when the
- // file for the user defined profile isn't found by the
- // profile manager.
+ for (String filename : unresolved) {
// TODO: work in progress, see issue 5039
-// addUserDefinedProfile(fileName, xmi, profileManager);
-// profile = getMatchingUserDefinedProfile(fileName,
-// profileManager);
-// assert profile != null
-// : "Profile should have been found now.";
+// addUserDefinedProfile(filename, xmi, profileManager);
+// Profile profile = getMatchingUserDefinedProfile(filename,
+// profileManager);
+// assert profile != null : "Profile should have been found now.";
+// profiles.add(profile);
}
- return profile;
+ return profiles;
}
/**
@@ -216,21 +155,6 @@
}
}
- private static Profile getMatchingUserDefinedProfile(String fileName,
- ProfileManager profileManager) {
- for (Profile candidateProfile
- : profileManager.getRegisteredProfiles()) {
- if (candidateProfile instanceof UserDefinedProfile) {
- UserDefinedProfile userProfile =
- (UserDefinedProfile) candidateProfile;
- if (userProfile.getModelFile() != null
- && fileName.equals(userProfile.getModelFile().getName())) {
- return userProfile;
- }
- }
- }
- return null;
- }
private static File getProfilesDirectory(ProfileManager profileManager) {
if (isSomeProfileDirectoryConfigured(profileManager)) {
@@ -275,13 +199,12 @@
ProfileConfiguration pc = (ProfileConfiguration) member;
w.println("<?xml version = \"1.0\" encoding = \"UTF-8\" ?>");
- w.println("<!DOCTYPE profile SYSTEM \"profile.dtd\" >");
+ // TODO: This DTD doesn't exist, so we can't tell readers to
+ // look for it
+// w.println("<!DOCTYPE profile SYSTEM \"profile.dtd\" >");
w.println("<profile>");
- Iterator it = pc.getProfiles().iterator();
- while (it.hasNext()) {
- Profile profile = (Profile) it.next();
-
+ for (Profile profile : pc.getProfiles()) {
if (profile instanceof UserDefinedProfile) {
UserDefinedProfile uprofile =
(UserDefinedProfile) profile;
@@ -340,5 +263,237 @@
throw new OpenException(e);
}
}
-
+
}
+
+/**
+ * Parser for Profile Configuration.
+ *
+ * @author Tom Morris <[email protected]>
+ */
+class ProfileConfigurationParser extends SAXParserBase {
+
+ private static final Logger LOG = Logger
+ .getLogger(ProfileConfigurationParser.class);
+
+ private ProfileConfigurationTokenTable tokens =
+ new ProfileConfigurationTokenTable();
+
+ private Profile profile;
+
+ private String model;
+
+ private String filename;
+
+ private Collection<Profile> profiles = new ArrayList<Profile>();
+
+ private Collection<String> unresolvedFilenames = new ArrayList<String>();
+
+ /**
+ * Construct the parser.
+ */
+ public ProfileConfigurationParser() {
+ // Empty constructor
+ }
+
+ public Collection<Profile> getProfiles() {
+ return profiles;
+ }
+
+ public Collection<String> getUnresolvedFilenames() {
+ return unresolvedFilenames;
+ }
+
+ public void handleStartElement(XMLElement e) {
+
+ try {
+ switch (tokens.toToken(e.getName(), true)) {
+
+ case ProfileConfigurationTokenTable.TOKEN_PROFILE:
+ break;
+ case ProfileConfigurationTokenTable.TOKEN_PLUGIN:
+ profile = null;
+ break;
+ case ProfileConfigurationTokenTable.TOKEN_USER_DEFINED:
+ profile = null;
+ filename = null;
+ model = null;
+ break;
+ case ProfileConfigurationTokenTable.TOKEN_FILENAME:
+ break;
+ case ProfileConfigurationTokenTable.TOKEN_MODEL:
+ break;
+
+ default:
+ LOG.warn("WARNING: unknown tag:" + e.getName());
+ break;
+ }
+ } catch (Exception ex) {
+ LOG.error("Exception in startelement", ex);
+ }
+ }
+
+ /**
+ * Called by the XML implementation to signal the end of an XML entity.
+ *
+ * @param e The XML entity that ends.
+ * @throws SAXException on any error
+ */
+ public void handleEndElement(XMLElement e) throws SAXException {
+
+ try {
+ switch (tokens.toToken(e.getName(), false)) {
+
+ case ProfileConfigurationTokenTable.TOKEN_PROFILE:
+ handleProfileEnd(e);
+ break;
+ case ProfileConfigurationTokenTable.TOKEN_PLUGIN:
+ handlePluginEnd(e);
+ break;
+ case ProfileConfigurationTokenTable.TOKEN_USER_DEFINED:
+ handleUserDefinedEnd(e);
+ break;
+ case ProfileConfigurationTokenTable.TOKEN_FILENAME:
+ handleFilenameEnd(e);
+ break;
+ case ProfileConfigurationTokenTable.TOKEN_MODEL:
+ handleModelEnd(e);
+ break;
+
+ default:
+ LOG.warn("WARNING: unknown end tag:" + e.getName());
+ break;
+ }
+ } catch (Exception ex) {
+ throw new SAXException(ex);
+ }
+ }
+
+ protected void handleProfileEnd(XMLElement e) {
+ if (profiles.isEmpty()) {
+ LOG.warn("No profiles defined");
+ }
+ }
+
+ protected void handlePluginEnd(XMLElement e) throws SAXException {
+ String name = e.getText().trim();
+ profile = lookupProfile(name);
+ if (profile != null) {
+ profiles.add(profile);
+ LOG.debug("Found plugin profile " + name);
+ } else {
+ LOG.error("Unabled to find plugin profile - " + name);
+ }
+ }
+
+ private static Profile lookupProfile(String profileIdentifier)
+ throws SAXException {
+ Profile profile;
+ profile = ProfileFacade.getManager().lookForRegisteredProfile(
+ profileIdentifier);
+ if (profile == null) {
+
+ // for compatibility with older format
+ profile = ProfileFacade.getManager().getProfileForClass(
+ profileIdentifier);
+
+ if (profile == null) {
+ throw new SAXException("Plugin profile \"" + profileIdentifier
+ + "\" is not available in installation.", null);
+ }
+ }
+ return profile;
+ }
+
+ protected void handleUserDefinedEnd(XMLElement e) {
+ // <model> is not used in current implementation
+ if (filename == null /* || model == null */) {
+ LOG.error("Got badly formed user defined profile entry " + e);
+ }
+ profile = getMatchingUserDefinedProfile(filename, ProfileFacade
+ .getManager());
+
+ if (profile == null) {
+ unresolvedFilenames.add(filename);
+ } else {
+ profiles.add(profile);
+ LOG.debug("Loaded user defined profile - filename = " + filename);
+ }
+
+ }
+
+ private static Profile getMatchingUserDefinedProfile(String fileName,
+ ProfileManager profileManager) {
+ for (Profile candidateProfile
+ : profileManager.getRegisteredProfiles()) {
+ if (candidateProfile instanceof UserDefinedProfile) {
+ UserDefinedProfile userProfile =
+ (UserDefinedProfile) candidateProfile;
+ if (userProfile.getModelFile() != null
+ && fileName
+ .equals(userProfile.getModelFile().getName())) {
+ return userProfile;
+ }
+ }
+ }
+ return null;
+ }
+
+ protected void handleFilenameEnd(XMLElement e) {
+ filename = e.getText().trim();
+ LOG.debug("Got filename = " + filename);
+ }
+
+ protected void handleModelEnd(XMLElement e) {
+ model = e.getText().trim();
+ LOG.debug("Got model = " + model);
+ }
+
+ /**
+ * Token Table for Profile Configuration parser.
+ *
+ * @author Tom Morris
+ */
+ class ProfileConfigurationTokenTable extends XMLTokenTableBase {
+
+ private static final String STRING_PROFILE = "profile";
+
+ private static final String STRING_PLUGIN = "plugin";
+
+ private static final String STRING_USER_DEFINED = "userDefined";
+
+ private static final String STRING_FILENAME = "filename";
+
+ private static final String STRING_MODEL = "model";
+
+ public static final int TOKEN_PROFILE = 1;
+
+ public static final int TOKEN_PLUGIN = 2;
+
+ public static final int TOKEN_USER_DEFINED = 3;
+
+ public static final int TOKEN_FILENAME = 4;
+
+ public static final int TOKEN_MODEL = 5;
+
+ private static final int TOKEN_LAST = 5;
+
+ public static final int TOKEN_UNDEFINED = 999;
+
+ /**
+ * Construct the token table.,
+ */
+ public ProfileConfigurationTokenTable() {
+ super(TOKEN_LAST);
+ }
+
+ protected void setupTokens() {
+ addToken(STRING_PROFILE, Integer.valueOf(TOKEN_PROFILE));
+ addToken(STRING_PLUGIN, Integer.valueOf(TOKEN_PLUGIN));
+ addToken(STRING_USER_DEFINED, Integer.valueOf(TOKEN_USER_DEFINED));
+ addToken(STRING_FILENAME, Integer.valueOf(TOKEN_FILENAME));
+ addToken(STRING_MODEL, Integer.valueOf(TOKEN_MODEL));
+ }
+ }
+
+}
\ No newline at end of file
Modified: trunk/src/argouml-app/tests/org/argouml/persistence/TestProfileConfigurationFilePersister.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/persistence/TestProfileConfigurationFilePersister.java?view=diff&pathrev=16688&r1=16687&r2=16688
==============================================================================
--- trunk/src/argouml-app/tests/org/argouml/persistence/TestProfileConfigurationFilePersister.java (original)
+++ trunk/src/argouml-app/tests/org/argouml/persistence/TestProfileConfigurationFilePersister.java 2009-01-23 13:11:04-0800
@@ -24,24 +24,41 @@
package org.argouml.persistence;
+import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Iterator;
import junit.framework.TestCase;
+import org.argouml.application.api.Argo;
+import org.argouml.kernel.ProfileConfiguration;
+import org.argouml.kernel.Project;
+import org.argouml.kernel.ProjectManager;
import org.argouml.model.InitializeModel;
import org.argouml.model.Model;
import org.argouml.model.UmlException;
import org.argouml.model.XmiWriter;
import org.argouml.profile.CoreProfileReference;
import org.argouml.profile.FileModelLoader;
+import org.argouml.profile.Profile;
import org.argouml.profile.ProfileException;
import org.argouml.profile.ProfileModelLoader;
import org.argouml.profile.ResourceModelLoader;
import org.argouml.profile.UserProfileReference;
+import org.argouml.profile.init.InitProfileSubsystem;
+import org.argouml.profile.internal.ProfileJava;
+import org.argouml.profile.internal.ProfileUML;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
/**
* Tests for the {@link ProfileConfigurationFilePersister} class.
@@ -54,10 +71,11 @@
protected void setUp() throws Exception {
super.setUp();
InitializeModel.initializeDefault();
+ new InitProfileSubsystem().init();
}
/**
- * Demonstrates that XmiWriterMDRImpl fails to write a profile
+ * Tests whether XmiWriterMDRImpl fails to write a profile
* (i.e., the file will contain no model) previously loaded from a file.
*
* @throws ProfileException if the loading of the profile fails.
@@ -90,4 +108,91 @@
assertEquals(umlModelName, Model.getFacade().getName(umlModel));
}
+ private static final String TEST_PROFILE =
+ "<?xml version = \"1.0\" encoding = \"UTF-8\" ?>\n"
+ // Although we've historically written out the DOCTYPE, the DTD doesn't
+ // actually exist and this line will get stripped by the .uml file
+ // persister
+// + "<!DOCTYPE profile SYSTEM \"profile.dtd\" >\n"
+ + "<profile>\n"
+
+ // Standard UML 1.4 profile
+ + "\t\t<plugin>\n"
+ + "\t\t\tUML 1.4\n"
+ + "\t\t</plugin>\n"
+
+ // Standard Java profile
+ + "\t\t<plugin>\n"
+ + "\t\t\tJava\n"
+ + "\t\t</plugin>\n"
+
+
+ // TODO: User defined profile support untested currently
+// + "\t\t<userDefined>\n"
+// + "\t\t\t<filename>\n"
+// + "foo.profile\n"
+// + "</filename>\n"
+// + "\t\t\t<model>\n"
+// + "foo.profile.package\n"
+// + "\t\t\t</model>\n"
+// + "\t\t</userDefined>\n"
+
+ + "</profile>";
+
+ /**
+ * Test the basic profile configuration parser.
+ *
+ * @throws SAXException on a parse failure
+ * @throws UnsupportedEncodingException if our default encoding (UTF-8) is
+ * unsupported. Should never happen.
+ */
+ public void testProfileConfigurationParser() throws SAXException,
+ UnsupportedEncodingException {
+ InputStream inStream =
+ new ByteArrayInputStream(
+ TEST_PROFILE.getBytes(Argo.getEncoding()));
+ ProfileConfigurationParser parser = new ProfileConfigurationParser();
+ parser.parse(new InputSource(inStream));
+ Collection<Profile> profiles = parser.getProfiles();
+ assertEquals("Wrong number of profiles", 2, profiles.size());
+ Iterator<Profile> profileIter = profiles.iterator();
+ assertTrue("Didn't get expected UML profile",
+ profileIter.next() instanceof ProfileUML);
+ assertTrue("Didn't get expected Java profile",
+ profileIter.next() instanceof ProfileJava);
+ }
+
+ /**
+ * Test that we can save and restore the default profile configuration.
+ *
+ * @throws IOException on io error
+ * @throws SaveException on save error
+ * @throws OpenException on load error
+ */
+ public void testSaveLoadDefaultConfiguration() throws IOException,
+ SaveException, OpenException {
+
+ // Create a default profile and record its contents
+ Project project = ProjectManager.getManager().makeEmptyProject();
+ ProfileConfiguration pc = new ProfileConfiguration(project);
+ Collection<Profile> startingProfiles =
+ new ArrayList<Profile>(pc.getProfiles());
+
+ // Write the profile out to a temp file
+ ProfileConfigurationFilePersister persister =
+ new ProfileConfigurationFilePersister();
+ File file = File.createTempFile(this.getName(), ".profile");
+ OutputStream outStream = new FileOutputStream(file);
+ persister.save(pc, outStream);
+ outStream.close();
+
+ // Read it back in to a new empty project
+ InputStream inStream = new FileInputStream(file);
+ project = ProjectManager.getManager().makeEmptyProject();
+ persister.load(project, inStream);
+
+ // Make sure we got what we started with
+ assertEquals(startingProfiles,
+ project.getProfileConfiguration().getProfiles());
+ }
}
------------------------------------------------------
http://argouml.tigris.org/ds/viewMessage.do?dsForumId=5905&dsMessageId=1045380
To unsubscribe from this discussion, e-mail: [[email protected]].