3535import java .io .File ;
3636import java .io .FileReader ;
3737import java .io .IOException ;
38+ import java .io .InputStreamReader ;
3839import java .io .Reader ;
3940import java .io .StringReader ;
41+ import java .net .MalformedURLException ;
42+ import java .net .URL ;
4043import java .text .SimpleDateFormat ;
4144import java .util .ArrayList ;
4245import java .util .Date ;
@@ -76,6 +79,7 @@ public class ScriptInfo extends AbstractModuleInfo implements Contextual {
7679
7780 private static final int PARAM_CHAR_MAX = 640 * 1024 ; // should be enough ;-)
7881
82+ private final URL url ;
7983 private final String path ;
8084 private final String script ;
8185
@@ -105,7 +109,7 @@ public class ScriptInfo extends AbstractModuleInfo implements Contextual {
105109 * @param file The script file.
106110 */
107111 public ScriptInfo (final Context context , final File file ) {
108- this (context , file .getPath ());
112+ this (context , null , file .getPath (), null );
109113 }
110114
111115 /**
@@ -116,7 +120,23 @@ public ScriptInfo(final Context context, final File file) {
116120 * @param path Path to the script file.
117121 */
118122 public ScriptInfo (final Context context , final String path ) {
119- this (context , path , null );
123+ this (context , null , path , null );
124+ }
125+
126+ /**
127+ * Creates a script metadata object which describes a script at the given URL.
128+ *
129+ * @param context The SciJava application context to use when populating
130+ * service inputs.
131+ * @param url URL which references the script.
132+ * @param path Pseudo-path to the script file. This file does not actually
133+ * need to exist, but rather provides a name for the script with file
134+ * extension.
135+ */
136+ public ScriptInfo (final Context context , final URL url , final String path )
137+ throws IOException
138+ {
139+ this (context , url , path , new InputStreamReader (url .openStream ()));
120140 }
121141
122142 /**
@@ -132,9 +152,16 @@ public ScriptInfo(final Context context, final String path) {
132152 */
133153 public ScriptInfo (final Context context , final String path ,
134154 final Reader reader )
155+ {
156+ this (context , null , path , reader );
157+ }
158+
159+ private ScriptInfo (final Context context , final URL url , final String path ,
160+ final Reader reader )
135161 {
136162 setContext (context );
137- this .path = path ;
163+ this .url = url (url , path );
164+ this .path = path (url , path );
138165
139166 String contents = null ;
140167 if (reader != null ) {
@@ -150,6 +177,26 @@ public ScriptInfo(final Context context, final String path,
150177
151178 // -- ScriptInfo methods --
152179
180+ /**
181+ * Gets the URL of the script.
182+ * <p>
183+ * If the actual source of the script is a URL (provided via
184+ * {@link #ScriptInfo(Context, URL, String)}), then this will return it.
185+ * </p>
186+ * <p>
187+ * Alternately, if the path (from {@link #getPath()}) is a real file on disk
188+ * (provided via {@link #ScriptInfo(Context, File)} or
189+ * {@link #ScriptInfo(Context, String)}), then the URL returned here will be a
190+ * {@code file://} one reference to it.
191+ * </p>
192+ * <p>
193+ * Otherwise, this method will return null.
194+ * </p>
195+ */
196+ public URL getURL () {
197+ return url ;
198+ }
199+
153200 /**
154201 * Gets the path to the script on disk.
155202 * <p>
@@ -332,6 +379,21 @@ public String getVersion() {
332379
333380 // -- Helper methods --
334381
382+ private URL url (final URL u , final String p ) {
383+ if (u != null ) return u ;
384+ try {
385+ return new File (p ).toURI ().toURL ();
386+ }
387+ catch (final MalformedURLException exc ) {
388+ log .debug ("Cannot glean URL from path: " + p , exc );
389+ return null ;
390+ }
391+ }
392+
393+ private String path (final URL u , final String p ) {
394+ return p == null ? u .getPath () : p ;
395+ }
396+
335397 private void parseParam (final String param ) throws ScriptException {
336398 final int lParen = param .indexOf ("(" );
337399 final int rParen = param .lastIndexOf (")" );
0 commit comments