1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package sfutils;
29
30 import java.io.IOException;
31
32 import java.util.Collections;
33 import java.util.Map;
34 import java.util.WeakHashMap;
35
36 import com.meterware.httpunit.GetMethodWebRequest;
37 import com.meterware.httpunit.HttpUnitOptions;
38 import com.meterware.httpunit.WebConversation;
39 import com.meterware.httpunit.WebLink;
40 import com.meterware.httpunit.WebResponse;
41
42 import org.xml.sax.SAXException;
43
44 /***
45 * A utility class that provides access to small, core bits of information from
46 * the <a href="http://sourceforge.net/">SourceForge</a> website.
47 *
48 * @author <a href="mailto:ljnelson94@alumni.amherst.edu">Laird Nelson</a>
49 * @version $Revision: 1.4 $ $Date: 2004/07/27 20:20:36 $
50 * @since July 12, 2003
51 */
52 public final class SourceForge {
53
54 /***
55 * The leading portion of the URL required to access a <a
56 * href="http://sourceforge.net/">SourceForge</a> project.
57 */
58 private static final String PROJECT_PREFIX =
59 "http://sourceforge.net/projects/";
60
61 /***
62 * A {@link Map} of project IDs indexed by project short names. This field is
63 * thread-safe.
64 */
65 private static final Map PROJECT_ID_MAP =
66 Collections.synchronizedMap(new WeakHashMap());
67
68 /***
69 * Static initializer; ensures that the {@link
70 * HttpUnitOptions#setExceptionsThrownOnScriptError(boolean)} method is called
71 * with <code>false</code> as its parameter to work around the fact that <a
72 * href="http://sourceforge.net/">SourceForge</a> pages have JavaScript errors
73 * in them.
74 */
75 static {
76 HttpUnitOptions.setExceptionsThrownOnScriptError(false);
77 HttpUnitOptions.setScriptingEnabled(false);
78 }
79
80 /***
81 * Throws an {@link UnsupportedOperationException} when invoked.
82 *
83 * @exception UnsupportedOperationException
84 * when invoked
85 */
86 private SourceForge() throws UnsupportedOperationException {
87 super();
88 throw new UnsupportedOperationException();
89 }
90
91 /***
92 * Returns the <a href="http://sourceforge.net/">SourceForge</a> project
93 * identifier given a project short name. This method may return
94 * <code>null</code>.
95 *
96 * @param projectShortName
97 * the name of the project whose identifier should be returned;
98 * may be <code>null</code> in which case <code>null</code> will
99 * be returned
100 * @return the identifier corresponding to the <a
101 * href="http://sourceforge.net/">SourceForge</a> project with
102 * the supplied short name, or <code>null</code>
103 * @exception SourceForgeException
104 * if an error occurs
105 */
106 public static final String getProjectID(final String projectShortName)
107 throws SourceForgeException {
108 if (projectShortName == null) {
109 return null;
110 }
111 String projectID = (String)PROJECT_ID_MAP.get(projectShortName);
112 if (projectID != null) {
113 return projectID;
114 }
115 try {
116 final WebConversation webConversation = new WebConversation();
117 final WebResponse summaryPage =
118 webConversation.getResponse(new GetMethodWebRequest(PROJECT_PREFIX +
119 projectShortName));
120 assert summaryPage != null;
121 final WebLink viewMembersLink = summaryPage.getLinkWith("[View Members]");
122 if (viewMembersLink == null) {
123
124 final String text = summaryPage.getText();
125 assert text != null;
126 if (text.indexOf("Invalid Project") >= 0) {
127 throw new NoSuchProjectException(projectShortName);
128 }
129
130 throw new SourceForgeUIChangeException();
131 }
132 final String linkText = viewMembersLink.getURLString();
133 assert linkText != null;
134 final int groupIDIndex = linkText.indexOf("?group_id=");
135 if (groupIDIndex < 0) {
136 throw new SourceForgeUIChangeException();
137 }
138 projectID = linkText.substring(groupIDIndex + "?group_id=".length());
139 PROJECT_ID_MAP.put(projectShortName, projectID);
140 return projectID;
141 } catch (final IOException kaboom) {
142 throw new SourceForgeException(kaboom);
143 } catch (final SAXException kaboom) {
144 throw new SourceForgeException(kaboom);
145 }
146 }
147
148 }