source: trunk/www/admin/plugindefinitions/index.jsp @ 4889

Last change on this file since 4889 was 4889, checked in by Nicklas Nordborg, 13 years ago

References #1290: Change source files to UTF-8

Changed 'Hakkinen' to 'Häkkinen'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 20.6 KB
Line 
1<%-- $Id: index.jsp 4889 2009-04-06 12:52:39Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) 2005 Nicklas Nordborg
4  Copyright (C) 2006 Jari Häkkinen, Nicklas Nordborg, Martin Svensson
5  Copyright (C) 2007 Nicklas Nordborg
6
7  This file is part of BASE - BioArray Software Environment.
8  Available at http://base.thep.lu.se/
9
10  BASE is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License
12  as published by the Free Software Foundation; either version 3
13  of the License, or (at your option) any later version.
14
15  BASE is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License
21  along with BASE. If not, see <http://www.gnu.org/licenses/>.
22  ------------------------------------------------------------------
23
24  @author Nicklas
25  @version 2.0
26--%>
27<%@ page session="false"
28  import="net.sf.basedb.core.Application"
29  import="net.sf.basedb.core.SessionControl"
30  import="net.sf.basedb.core.DbControl"
31  import="net.sf.basedb.core.Item"
32  import="net.sf.basedb.core.Include"
33  import="net.sf.basedb.core.PluginDefinition"
34  import="net.sf.basedb.core.JobAgent"
35  import="net.sf.basedb.core.JobAgentSettings"
36  import="net.sf.basedb.core.ItemQuery"
37  import="net.sf.basedb.core.ItemResultList"
38  import="net.sf.basedb.core.Permission"
39  import="net.sf.basedb.core.ItemContext"
40  import="net.sf.basedb.core.MultiPermissions"
41  import="net.sf.basedb.core.OwnedItem"
42  import="net.sf.basedb.core.BaseException"
43  import="net.sf.basedb.core.PermissionDeniedException"
44  import="net.sf.basedb.core.ItemAlreadyExistsException"
45  import="net.sf.basedb.core.RoleKey"
46  import="net.sf.basedb.core.plugin.Plugin"
47  import="net.sf.basedb.core.query.Hql"
48  import="net.sf.basedb.util.FileUtil"
49  import="net.sf.basedb.util.PluginInfo"
50  import="net.sf.basedb.util.PluginConfigInfo"
51  import="net.sf.basedb.util.RemovableUtil"
52  import="net.sf.basedb.util.ShareableUtil"
53  import="net.sf.basedb.util.OwnableUtil"
54  import="net.sf.basedb.util.JarClassLoader"
55  import="net.sf.basedb.util.RegexpFileFilter"
56  import="net.sf.basedb.clients.web.Base"
57  import="net.sf.basedb.clients.web.PermissionUtil"
58  import="net.sf.basedb.clients.web.WebException"
59  import="net.sf.basedb.util.Values"
60  import="net.sf.basedb.clients.web.util.HTML"
61  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
62  import="net.sf.basedb.plugins.PluginConfigurationImporter"
63  import="java.util.Enumeration"
64  import="java.util.Set"
65  import="java.util.Map"
66  import="java.util.LinkedHashMap"
67  import="java.util.HashMap"
68  import="java.util.HashSet"
69  import="java.util.List"
70  import="java.util.LinkedList"
71  import="java.util.Collections"
72  import="java.io.FileFilter"
73%>
74<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
75<%!
76  private static final ItemContext defaultContext = Base.createDefaultContext("name", "name,pluginType,className,description");
77  private static final Item itemType = Item.PLUGINDEFINITION;
78%>
79<%
80final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
81final String ID = sc.getId();
82final String cmd = request.getParameter("cmd");
83final String root = request.getContextPath()+"/";
84final String mode = request.getParameter("mode");
85final String callback = request.getParameter("callback");
86final String itemId = request.getParameter("item_id");
87final String listPage = "list_plugins.jsp?ID="+ID
88  +(mode == null ? "" : "&mode="+mode)
89  +(callback == null ? "" : "&callback="+callback)
90  +(itemId == null ? "" : "&item_id="+itemId);
91final String viewPage = "view_plugin.jsp?ID="+ID;
92final String editPage = "edit_plugin.jsp?ID="+ID;
93
94String forward = null;
95String redirect = null;
96String message = null;
97DbControl dc = null;
98
99try
100{
101  if (cmd == null || "List".equals(cmd))
102  {
103    // Display the list page without updatinging the current context
104    Base.getAndSetCurrentContext(sc, itemType, null, defaultContext, true);
105    redirect = listPage;
106  }
107  else if ("UpdateContext".equals(cmd))
108  {
109    // Display the list page after updating the current context from the request parameters
110    Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
111    redirect = listPage;
112  }
113  else if ("LoadContext".equals(cmd))
114  {
115    // Display the list page after loading a saved context
116    int contextId = Values.getInt(request.getParameter("context"));
117    Base.loadContext(sc, contextId, defaultContext);
118    redirect = listPage;
119  }
120
121  else if ("ViewItem".equals(cmd))
122  {
123    // Display the view page for a single item
124    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
125    forward = viewPage;
126  }
127  else if ("EditItem".equals(cmd))
128  {
129    // Display the edit page for a single item (should be opened in a popup)
130    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
131    forward = editPage;
132  }
133  else if ("NewItem".equals(cmd))
134  {
135    // Display the edit page for a new item (should be opened in a popup)
136    if (!sc.hasPermission(Permission.CREATE, itemType))
137    {
138      throw new PermissionDeniedException(Permission.CREATE, itemType.toString());
139    }
140    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
141    cc.setId(0);
142   
143    redirect = "select_installation_type.jsp?ID="+ID;
144  }
145  else if("InstallationType".equals(cmd))
146  {
147    //Either manually or auto installation is selected
148    String type = request.getParameter("installationType");
149    if ("auto".equals(type))
150    {
151      forward = "auto_install.jsp?ID="+ID;
152    }
153    else
154    {
155      redirect = editPage;
156    }
157  }
158  else if("LoadPlugins".equals(cmd))
159  {
160    //Loads and install plugins that have been selected in auto_installer.jsp
161    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, null, defaultContext);
162    dc = sc.newDbControl();
163    java.io.File pluginDir = Application.getNonCorePluginDirectory();
164    java.io.File extensionsDir = new java.io.File(application.getRealPath(ExtensionsControl.EXTENSIONS_URL));
165    FileFilter jarFilter = new RegexpFileFilter(".*\\.jar", null);
166    List<java.io.File> jarFiles = new LinkedList<java.io.File>();
167    if (Values.getBoolean(request.getParameter("plugindir")))
168    {
169      jarFiles.addAll(FileUtil.findFiles(pluginDir, jarFilter));
170    }
171    if (Values.getBoolean(request.getParameter("extensionsdir")))
172    {
173      jarFiles.addAll(FileUtil.findFiles(extensionsDir, jarFilter));
174    }
175   
176    List<PluginInfo> pluginInfos = new LinkedList<PluginInfo>();
177    Map<PluginInfo, Throwable> installationResult = new LinkedHashMap<PluginInfo, Throwable>();
178   
179    //Get information about all plugins in jar-files that were found.
180    for (java.io.File file : jarFiles)
181    {
182      pluginInfos.addAll(PluginInfo.loadFromJar(file));
183    }
184    //Load selected plugins.
185    for (PluginInfo info : pluginInfos)
186    {
187      String selectedOption = request.getParameter(info.getJarPath() + ":" + info.getClassName());
188      if (selectedOption == null) selectedOption = "";     
189      boolean isInstalled = Values.getBoolean(request.getParameter(info.getClassName()+":isInstalled"));
190      boolean inSameJarFile = Values.getBoolean(request.getParameter(info.getClassName()+":inSameJarFile"));
191      if (selectedOption.equals("plugin") || selectedOption.equals("plugin+confs"))
192      {
193        //The plugin doesn't exists
194        if (!isInstalled)
195        {
196          PluginDefinition pd = null;
197          try
198          {
199            pd = PluginDefinition.getNew(dc, info.getClassName(), info.getJarPath(), true);
200            installationResult.put(info, null);
201          }
202          catch (Throwable t)
203          {
204            installationResult.put(info, new BaseException("Could not install: " + 
205                info.getClassName() + " in jar:" + info.getJarPath(), t));
206          }
207          if (pd != null)
208          {
209            dc.saveItem(pd);
210            pd.setTrusted(Values.getBoolean(request.getParameter(info.getClassName()+":trusted")));
211            String aie = Values.getStringOrNull(request.getParameter(info.getClassName()+":immediate_execution"));
212            pd.setAllowImmediateExecution(aie == null ? 
213              pd.getMainType() == Plugin.MainType.EXPORT : Values.getBoolean(aie));           
214          }
215        }
216        //The plugin exists but in a different jar, this will change the plugin's jarpath
217        else if (isInstalled && !inSameJarFile)
218        {
219          try 
220          {
221            PluginDefinition pd = PluginDefinition.getByClassName(dc, info.getClassName());
222            pd.loadPluginInformation(info.getJarPath(), info.getClassName(), true);
223            installationResult.put(info, null);
224          }
225          catch (Throwable t)
226          {
227            installationResult.put(info, new BaseException("Could not install: " + 
228                info.getClassName() + " in jar:" + info.getJarPath(), t));
229          }
230        }
231      }     
232    }
233    dc.commit();
234   
235    //Import selected configurations for each plugin in pluginInfos
236    dc = sc.newDbControl();
237    for (PluginInfo info : pluginInfos)
238    {
239      if (installationResult.get(info) != null) continue;
240     
241      List<PluginConfigInfo> configInfos = info.getConfigurations();
242      if (configInfos != null && configInfos.size() > 0)
243      {
244        HashMap<Integer, Boolean> configurations = new HashMap<Integer, Boolean>();
245        for (PluginConfigInfo cnfInfo : configInfos)
246        {
247          Boolean toImport = Values.getBoolean(request.getParameter(info.getClassName() + ":config:" + cnfInfo.getName()));
248          configurations.put(cnfInfo.getOrderInXml(), toImport);
249        }
250        try 
251        {
252          PluginConfigurationImporter configImporter = new PluginConfigurationImporter();
253          configImporter.init(sc, null, null);
254          configImporter.importPluginConfigurationsFromJar(info.getJarPath(), info.getConfigurationsPath(), configurations, false, true );
255        }
256        catch (Throwable t)
257        {
258          installationResult.put(info, 
259              new BaseException("Could not import configuration for: " + 
260              info.getClassName() + " in jar:" + info.getJarPath(), t));
261        }
262      }
263    }
264   
265    for (Map.Entry<PluginInfo, Throwable> entry : installationResult.entrySet())
266    {
267      Throwable t = entry.getValue();
268      if (t != null) t.printStackTrace();
269    }
270   
271    sc.setSessionSetting("pluginwizard.installationresult", installationResult);
272    redirect = "auto_install_result.jsp?ID=" + ID;
273  }
274  else if ("UpdateItem".equals(cmd))
275  {
276    // Update the properties on an item (will close the popup)
277    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, null, defaultContext);
278    dc = sc.newDbControl();
279    PluginDefinition plugin = (PluginDefinition)cc.getObject("item");
280    String className = Values.getStringOrNull(request.getParameter("className"));
281    String jarPath = Values.getStringOrNull(request.getParameter("jarPath"));
282    int usePermissions = Values.getInt(request.getParameter("use_permissions"));
283    if (plugin == null)
284    {
285      plugin = PluginDefinition.getNew(dc, className, jarPath, usePermissions == 2);
286      message = "Plugin created";
287      dc.saveItem(plugin);
288    }
289    else
290    {
291      dc.reattachItem(plugin);
292      plugin.loadPluginInformation(jarPath, className, usePermissions == 2);
293      message = "Plugin updated";
294    }
295    plugin.setMaxMemory(Values.parseBytes(request.getParameter("maxMemory"), null));
296    plugin.setTrusted(Values.getBoolean(request.getParameter("trusted")));
297    plugin.setUseInternalJobQueue(Values.getBoolean(request.getParameter("use_internal_jobqueue")));
298    String aie = Values.getStringOrNull(request.getParameter("allow_immediate_execution"));
299    plugin.setAllowImmediateExecution(aie == null ? 
300      plugin.getMainType() == Plugin.MainType.EXPORT : Values.getBoolean(aie));
301
302    //Update permissions
303    ItemQuery<RoleKey> q = RoleKey.getQuery();
304    q.setCacheResult(true);
305    ItemResultList<RoleKey> roleKeys = q.list(dc);
306    for (RoleKey key : roleKeys)
307    {
308      String name = key.getItemType().name();
309      int granted = Values.getInt(request.getParameter(name+"_granted"));
310      int denied = Values.getInt(request.getParameter(name+"_denied"));
311      plugin.setPermissions(key, PermissionUtil.getPermissions(granted), PermissionUtil.getPermissions(denied));
312    }
313    plugin.setUsePermissions(usePermissions != 0);
314   
315    // Installed on job agents
316    String[] removeAgents = Values.getString(request.getParameter("removeAgents")).split(",");
317    for (int i = 0; i < removeAgents.length; ++i)
318    {
319      int agentId = Values.getInt(removeAgents[i], -1);
320      if (agentId != -1) 
321      {
322        JobAgent agent = JobAgent.getById(dc, agentId);
323        JobAgentSettings settings = agent.getSettings(plugin, false);
324        if (settings != null && settings.isInDatabase()) dc.deleteItem(settings);
325      }
326    }
327
328    String[] allAgents = Values.getString(request.getParameter("allAgents")).split(",");
329    for (int i = 0; i < allAgents.length; ++i)
330    {
331      int agentId = Values.getInt(allAgents[i], -1);
332      if (agentId != -1) 
333      {
334        JobAgent agent = JobAgent.getById(dc, agentId);
335        JobAgentSettings settings = agent.getSettings(plugin, true);
336        if (!settings.isInDatabase()) 
337        {
338          dc.saveItem(settings);
339        }
340        else
341        {
342          dc.reattachItem(settings);
343        }
344        settings.setJarPath(Values.getStringOrNull(request.getParameter("jarPath."+agentId)));
345        settings.setMaxMemory(Values.parseBytes(request.getParameter("maxMemory."+agentId), null));
346        settings.setPriorityBoost(Values.getInt(request.getParameter("priorityBoost."+agentId)));
347        String trusted = request.getParameter("trusted."+agentId);
348        settings.setTrusted(trusted == null ? null : Values.getBoolean(trusted));
349      }
350    }
351   
352    //Annotations
353    Base.updateAnnotations(dc, plugin, plugin, request);
354   
355    dc.commit();
356    cc.removeObject("item");
357  }
358  else if ("DeleteItem".equals(cmd))
359  {
360    // Delete a single item and then return to the view page
361    dc = sc.newDbControl();
362    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
363    RemovableUtil.setRemoved(dc, itemType, Collections.singleton(cc.getId()), true);
364    dc.commit();
365    redirect = viewPage;
366  }
367  else if ("DeleteItems".equals(cmd))
368  {
369    // Delete all selected items on the list page
370    dc = sc.newDbControl();
371    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
372    int numTotal = cc.getSelected().size();
373    int numRemoved = RemovableUtil.setRemoved(dc, itemType, cc.getSelected(), true);
374    dc.commit();
375    if (numTotal != numRemoved)
376    {
377      message = (numRemoved == 0 ? "No" : "Only "+numRemoved+" of "+numTotal) + " items could be deleted, because you have no DELETE permission";
378    }
379    redirect = listPage+(message != null ? "&popmessage="+HTML.urlEncode(message) : "");
380  }
381  else if ("RestoreItem".equals(cmd))
382  {
383    // Restore a single item and then return to the view page
384    dc = sc.newDbControl();
385    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
386    RemovableUtil.setRemoved(dc, itemType, Collections.singleton(cc.getId()), false);
387    dc.commit();
388    redirect = viewPage;
389  }
390  else if ("RestoreItems".equals(cmd))
391  {
392    // Restore all selected items on the list page
393    dc = sc.newDbControl();
394    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
395    int numTotal = cc.getSelected().size();
396    int numRemoved = RemovableUtil.setRemoved(dc, itemType, cc.getSelected(), false);
397    dc.commit();
398    if (numTotal != numRemoved)
399    {
400      message = (numRemoved == 0 ? "No" : "Only "+numRemoved+" of "+numTotal) + " items could be restored, because you have no WRITE permission";
401    }
402    redirect = listPage+(message != null ? "&popmessage="+HTML.urlEncode(message) : "");
403  }
404  else if ("ShareItem".equals(cmd))
405  {
406    // Display a popup window for sharing a single item
407    dc = sc.newDbControl();
408    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
409    MultiPermissions permissions = ShareableUtil.getMultiPermissions(dc, itemType, Collections.singleton(cc.getId()));
410    dc.close();
411    cc.setObject("MultiPermissions", permissions);
412    redirect = "../../common/share/share.jsp?ID="+ID+"&item_type="+itemType.name();
413  }
414  else if ("ShareItems".equals(cmd))
415  {
416    // Display a popup window for sharing all selected items on the list page
417    dc = sc.newDbControl();
418    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
419    MultiPermissions permissions = ShareableUtil.getMultiPermissions(dc, itemType, cc.getSelected());
420    dc.close();
421    cc.setObject("MultiPermissions", permissions);
422    redirect = "../../common/share/share.jsp?ID="+ID+"&item_type="+itemType.name();
423  }
424  else if ("SetOwnerOfItem".equals(cmd))
425  {
426    // Change owner of items selected on a list page
427    dc = sc.newDbControl();
428    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
429    OwnedItem item = (OwnedItem)itemType.getById(dc, cc.getId());
430    cc.setObject("OwnedItems", Collections.singleton(item));
431    redirect = "../../common/ownership/ownership.jsp?ID="+ID+"&item_type="+itemType.name();
432  }
433  else if ("SetOwnerOfItems".equals(cmd))
434  {
435    // Change owner of items selected on a list page
436    dc = sc.newDbControl();
437    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
438    Set<OwnedItem> items = new HashSet<OwnedItem>();
439    for (Integer id : cc.getSelected())
440    {
441      if (id != null) items.add((OwnedItem)itemType.getById(dc, id));
442    }
443    dc.close();
444    cc.setObject("OwnedItems", items);
445    redirect = "../../common/ownership/ownership.jsp?ID="+ID+"&item_type="+itemType.name();
446  }
447  else if ("ExportItems".equals(cmd))
448  {
449    // Run an export plugin in a list context
450    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
451    final ItemQuery<PluginDefinition> query = PluginDefinition.getQuery();
452    query.join(Hql.leftJoin("guiContexts", "ctx"));
453    query.setDistinct(true);
454    cc.configureQuery(query, true);
455    cc.setQuery(query);
456    redirect = "../../common/export/index.jsp?ID="+ID+"&cmd=SelectPlugin&item_type="+itemType.name()+"&context_type=LIST&title=Export+plugins";
457  }
458  else if ("ExportItem".equals(cmd))
459  {
460    // Run an export plugin in single-item context
461    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
462    redirect = "../../common/export/index.jsp?ID="+ID+"&cmd=SelectPlugin&item_type="+itemType.name()+"&context_type=ITEM&title=Export+plugin";
463  }
464  else if ("ImportItems".equals(cmd))
465  {
466    // Run an import plugin in a list context
467    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
468    final ItemQuery<PluginDefinition> query = PluginDefinition.getQuery();
469    query.join(Hql.leftJoin("guiContexts", "ctx"));
470    query.setDistinct(true);
471    cc.configureQuery(query, true);
472    cc.setQuery(query);
473    redirect = "../../common/import/index.jsp?ID="+ID+"&cmd=SelectPlugin&item_type="+itemType.name()+"&context_type=LIST&title=Import+plugins";
474  }
475  else if ("ImportItem".equals(cmd))
476  {
477    // Run an import plugin in single-item context
478    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
479    redirect = "../../common/import/index.jsp?ID="+ID+"&cmd=SelectPlugin&item_type="+itemType.name()+"&context_type=ITEM&title=Import+plugin";
480  }
481  else if ("RunListPlugin".equals(cmd))
482  {
483    // Run another plugin in a list context
484    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
485    final ItemQuery<PluginDefinition> query = PluginDefinition.getQuery();
486    query.join(Hql.leftJoin("guiContexts", "ctx"));
487    query.setDistinct(true);
488    cc.configureQuery(query, true);
489    cc.setQuery(query);
490    redirect = "../../common/plugin/index.jsp?ID="+ID+"&cmd=SelectPlugin&item_type="+itemType.name()+"&context_type=LIST&main_type=OTHER&title=Run+plugin";
491  }
492  else if ("RunPlugin".equals(cmd))
493  {
494    // Run another plugin in single-item context
495    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
496    redirect = "../../common/plugin/index.jsp?ID="+ID+"&cmd=SelectPlugin&item_type="+itemType.name()+"&context_type=ITEM&main_type=OTHER&title=Run+plugin";
497  }
498  else if ("UnloadItems".equals(cmd))
499  {
500    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
501    dc = sc.newDbControl();
502    for (int id : cc.getSelected())
503    {
504      PluginDefinition pd = PluginDefinition.getById(dc, id);
505      if (pd.getJarPath() != null)
506      {
507        JarClassLoader.unload(pd.getJarPath());
508      }
509    }
510    dc.close();
511    redirect = listPage;
512  }
513  else if ("UnloadItem".equals(cmd))
514  {
515    ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, pageContext, defaultContext);
516    dc = sc.newDbControl();
517    PluginDefinition pd = PluginDefinition.getById(dc, cc.getId());
518    if (pd.getJarPath() != null)
519    {
520      JarClassLoader.unload(pd.getJarPath());
521    }
522    dc.close();
523    redirect = viewPage;
524  }
525  else
526  {
527    throw new WebException("popup", "Invalid command", "The command {1} is not recognised as a valid command.", cmd);
528  }
529}
530finally
531{
532  if (dc != null) dc.close();
533}
534
535if (forward != null)
536{
537  pageContext.forward(forward);
538}
539else if (redirect != null)
540{
541  response.sendRedirect(redirect);
542}
543else if (message == null)
544{
545  response.sendRedirect(root + "common/close_popup.jsp?refresh_opener=1&wait=0");
546}
547else
548{
549  response.sendRedirect(root + "common/close_popup.jsp?refresh_opener=1&message="+HTML.urlEncode(message));
550}
551%>
552
Note: See TracBrowser for help on using the repository browser.