View Javadoc

1   /*
2    * Copyright 2010 Metastratus Web Solutions Limited. All Rights Reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.fatwire.gst.foundation.taglib.install;
17  
18  import java.io.File;
19  import java.io.FileInputStream;
20  import java.io.FileOutputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.LinkedHashMap;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Properties;
29  
30  import javax.servlet.ServletContext;
31  
32  import org.apache.commons.lang.StringUtils;
33  
34  import COM.FutureTense.Interfaces.FTValList;
35  import COM.FutureTense.Interfaces.ICS;
36  import COM.FutureTense.Interfaces.Utilities;
37  
38  import com.fatwire.assetapi.common.SiteAccessException;
39  import com.fatwire.assetapi.data.AssetId;
40  import com.fatwire.assetapi.site.User;
41  import com.fatwire.assetapi.site.UserManager;
42  import com.fatwire.gst.foundation.facade.logging.Log;
43  import com.fatwire.gst.foundation.facade.logging.LogUtil;
44  import com.fatwire.gst.foundation.facade.runtag.asset.AssetList;
45  import com.fatwire.gst.foundation.facade.runtag.publication.PublicationCreate;
46  import com.fatwire.gst.foundation.facade.runtag.publication.PublicationGather;
47  import com.fatwire.gst.foundation.facade.runtag.publication.PublicationGet;
48  import com.fatwire.gst.foundation.facade.runtag.publication.PublicationLoad;
49  import com.fatwire.gst.foundation.facade.runtag.publication.PublicationSave;
50  import com.fatwire.gst.foundation.facade.sql.SqlHelper;
51  import com.fatwire.gst.foundation.tagging.CacheMgrTaggedAssetEventListener;
52  import com.fatwire.gst.foundation.tagging.TaggedAssetEventListener;
53  import com.fatwire.gst.foundation.tagging.db.TableTaggingServiceImpl;
54  import com.fatwire.gst.foundation.url.WraAssetEventListener;
55  import com.fatwire.gst.foundation.url.db.UrlRegistryDaoImpl;
56  import com.fatwire.system.SessionFactory;
57  
58  /**
59   * General installer class to be used by JSP tag library. Also externally
60   * accessible.
61   * 
62   * @author Tony Field
63   * @author Dolf Dijkstra
64   * @since 2012-03-26
65   */
66  public final class InstallerEngine {
67      protected static final Log LOG = LogUtil.getLog(InstallStatus.class);
68  
69      public static final String[] GST_SITE_TREETABS = { "Active List", "Admin", "Bookmarks", "Site Plan" };
70  
71      /* Order of the components is important */
72      private final GSFComponent[] components = new GSFComponent[] { new PublicationComponent(),
73              new TagRegistryComponent(), new UrlRegistryComponent(), new AssemblerComponent(), new PageRefComponent(),
74              new GSTDispatcherComponent(), new FlexFamilyComponent(), new FlexAttributesComponent(),
75              new AttributesInFamilyComponent(), new DefinitionsComponent(), new UserInSiteComponent(),
76              new TreetabsInSiteComponent(), new CSElementSiteEntryInSiteComponent(), };
77  
78      private final ICS ics;
79      private final ServletContext ctx;
80      private final List<String> targetFlexFamilies;
81  
82      public InstallerEngine(ICS ics, ServletContext ctx, List<String> targetFlexFamilies) {
83          this.ics = ics;
84          this.ctx = ctx;
85          if (targetFlexFamilies == null || targetFlexFamilies.size() == 0) {
86              this.targetFlexFamilies = Arrays.asList("GSTAttribute");
87          } else {
88              this.targetFlexFamilies = targetFlexFamilies;
89          }
90      }
91  
92      public Map<GSFComponent, Boolean> getInstallStatus() {
93          Map<GSFComponent, Boolean> map = new LinkedHashMap<GSFComponent, Boolean>();
94          savePubid();
95  
96          for (GSFComponent c : components) {
97              map.put(c, c.isInstalled());
98          }
99          restorePubid();
100         return map;
101 
102     }
103 
104     /**
105      * Perform the install. Note this will only install components that are not
106      * already properly installed, and this determination is made based on the
107      * install status.
108      * 
109      */
110     protected void doInstall(List<String> toInstall) {
111         savePubid();
112         LOG.info("Installing missing GSF components");
113         for (GSFComponent c : components) {
114             if (toInstall.contains(c.getClass().getSimpleName())) {
115                 LOG.info("Installing GSF component " + c.getClass().getSimpleName());
116                 c.install();
117             }
118         }
119         LOG.info("GSF missing component install complete.");
120         restorePubid();
121     }
122 
123     class PublicationComponent implements GSFComponent {
124         @Override
125         public String getDescription() {
126             return "GST Site";
127         }
128 
129         public String getName() { return getClass().getSimpleName(); }
130 
131         @Override
132         public boolean isInstalled() {
133             // <PUBLICATION.LOAD NAME="pubtest" FIELD="name" VALUE="GST"/>
134             PublicationLoad load = new PublicationLoad();
135             load.setName("pubtest");
136             load.setField("name");
137             load.setValue("GST");
138             load.execute(ics);
139             return ics.GetErrno() == -101 ? false : true;
140 
141         }
142 
143         public boolean install() {
144             LOG.info("Installing Publication...");
145             // <SETVAR NAME="Publication:name" VALUE="GST"/>
146             // <SETVAR NAME="Publication:description" VALUE="GST site"/>
147             // <SETVAR NAME="Publication:cs_preview" VALUE="Variables.empty"/>
148             ics.SetVar("Publication:name", "GST");
149             ics.SetVar("Publicatin:description", "GST Site");
150             ics.SetVar("Publication:cs_preview", "");
151             // <SETVAR NAME="errno" VALUE="0"/>
152             ics.ClearErrno();
153             // <PUBLICATION.CREATE NAME="publication"/>
154             PublicationCreate pc = new PublicationCreate();
155             pc.setName("publication");
156             pc.execute(ics);
157             // <PUBLICATION.GATHER NAME="publication" PREFIX="Publication"/>
158             PublicationGather pg = new PublicationGather();
159             pg.setName("publication");
160             pg.setPrefix("Publication");
161             pg.execute(ics);
162             // <PUBLICATION.SAVE NAME="publication"/>
163             PublicationSave ps = new PublicationSave();
164             ps.setName("publication");
165             ps.execute(ics);
166             // <PUBLICATION.GET NAME="publication" FIELD="id" OUTPUT="pubid"/>
167             PublicationGet pGet = new PublicationGet();
168             pGet.setName("publication");
169             pGet.setField("id");
170             pGet.setOutput("pubid");
171             // <h2>Created GST site with id: <CSVAR
172             // NAME="Variables.pubid"/></h2>
173             LOG.info("...publication install complete.  Pubid: " + ics.GetVar("pubid"));
174             return true;
175         }
176 
177     }
178 
179     class TagRegistryComponent implements GSFComponent {
180         @Override
181         public String getDescription() {
182             return "Tag component listener";
183         }
184 
185         public String getName() { return getClass().getSimpleName(); }
186 
187         @Override
188         public boolean isInstalled() {
189             if (!new TableTaggingServiceImpl(ics).isInstalled())
190                 return false;
191             if (!new TaggedAssetEventListener().isInstalled(ics))
192                 return false;
193             if (!new CacheMgrTaggedAssetEventListener().isInstalled(ics))
194                 return false;
195             return true;
196         }
197 
198         public boolean install() {
199             LOG.info("Installing tag registry...");
200             new TableTaggingServiceImpl(ics).install();
201             new TaggedAssetEventListener().install(ics);
202             new CacheMgrTaggedAssetEventListener().install(ics);
203             LOG.info("...tag registry install complete");
204             return true;
205         }
206 
207     }
208 
209     class UrlRegistryComponent implements GSFComponent {
210         @Override
211         public String getDescription() {
212             return "URL Registry component";
213         }
214 
215         public String getName() { return getClass().getSimpleName(); }
216 
217         @Override
218         public boolean isInstalled() {
219             if (!new UrlRegistryDaoImpl(ics).isInstalled())
220                 return false;
221             if (!new WraAssetEventListener().isInstalled(ics))
222                 return false;
223             return true;
224         }
225 
226         public boolean install() {
227             LOG.info("Installing url registry...");
228             new UrlRegistryDaoImpl(ics).install();
229             new WraAssetEventListener().install(ics);
230             LOG.info("...url registry install complete");
231             return true;
232         }
233 
234     }
235 
236     class FlexFamilyComponent implements GSFComponent {
237         @Override
238         public String getDescription() {
239             return "Flex Family";
240         }
241 
242         public String getName() { return getClass().getSimpleName(); }
243 
244         @Override
245         public boolean isInstalled() {
246             for (String tbl : Arrays.asList("GSTFilter", "GSTAttribute", "GSTPDefinition", "GSTDefinition",
247                     "GSTParent", "GSTVirtualWebroot", "GSTAlias", "GSTProperty")) {
248                 if (SqlHelper.tableExists(ics, tbl) == false) {
249                     return false;
250                 }
251             }
252             return true;
253         }
254 
255         @Override
256         public boolean install() {
257             LOG.info("Installing flex family...");
258             ics.CallElement("GST/Foundation/FlexFamilyInstaller", null);
259             LOG.info("...flex family install complete");
260             return true;
261         }
262     }
263 
264     class FlexAttributesComponent implements GSFComponent {
265         @Override
266         public String getDescription() {
267             return "Flex Attributes";
268         }
269 
270         public String getName() { return getClass().getSimpleName(); }
271 
272         @Override
273         public boolean isInstalled() {
274             for (String name : Arrays.asList("env_name", "env_vwebroot", "master_vwebroot", "popup", "target_url",
275                     "value")) {
276                 if (!AssetList.assetExistsByName(ics, "GSTAttribute", name)) {
277                     return false;
278                 }
279             }
280             return true;
281         }
282 
283         @Override
284         public boolean install() {
285             LOG.info("Installing flex attributes...");
286             ics.CallElement("GST/Foundation/InstallAttributes", null);
287             LOG.info("...flex attributes install complete");
288             return true;
289         }
290     }
291 
292     class AttributesInFamilyComponent implements GSFComponent {
293         @Override
294         public String getDescription() {
295             return "Attributes";
296         }
297 
298         public String getName() { return getClass().getSimpleName(); }
299 
300         @Override
301         public boolean isInstalled() {
302             for (String family : targetFlexFamilies) {
303                 for (String attr : Arrays.asList("linktext", "linkimage", "gsttag", "h1title", "metadescription",
304                         "metakeyword", "metatitle")) {
305                     if (!AssetList.assetExistsByName(ics, family, attr)) {
306                         return false;
307                     }
308                 }
309             }
310             return true;
311         }
312 
313         /**
314          * Install the flex attributes into any flex family that is desired. By
315          * default, if no otherwise specified, they are installed into the
316          * GSTAttribute flex family.
317          */
318         @Override
319         public boolean install() {
320             for (String family : targetFlexFamilies) {
321                 LOG.info("Installing flex attributes into family " + family + "...");
322                 FTValList vl = new FTValList();
323                 vl.setValString("AttributeType", family);
324                 ics.CallElement("GST/Foundation/InstallAttributesIntoFamily", vl);
325                 LOG.info("...flex attribute installation into family " + family + " complete.");
326             }
327             return true;
328         }
329 
330     }
331 
332     class DefinitionsComponent implements GSFComponent {
333         @Override
334         public String getDescription() {
335             return "Flex Definitions";
336         }
337 
338         public String getName() { return getClass().getSimpleName(); }
339 
340         @Override
341         public boolean isInstalled() {
342             for (String def : Arrays.asList("GSTVirtualWebroot", "GSTAlias", "GSTProperty")) {
343                 if (!AssetList.assetExistsByName(ics, "GSTDefinition", def)) {
344                     return false;
345                 }
346             }
347             return true;
348         }
349 
350         @Override
351         public boolean install() {
352             LOG.info("Installing flex definitions...");
353             ics.CallElement("GST/Foundation/InstallDefinitions", null);
354             LOG.info("...flex definition install complete");
355             return true;
356         }
357     }
358 
359     class AssemblerComponent implements GSFComponent {
360         @Override
361         public boolean isInstalled() {
362             boolean result = false;
363             try {
364                 String srProps = ctx.getRealPath("/WEB-INF/classes/ServletRequest.properties");
365                 InputStream in = new FileInputStream(srProps);
366                 Properties prop = new Properties();
367                 prop.load(in);
368                 in.close();
369                 int i = 1;
370                 for (;;) {
371 
372                     String classname = prop.getProperty("uri.assembler." + i + ".classname");
373                     // out.write(classname +"<br/>");
374                     if (classname == null || classname.trim().length() == 0) {
375                         i--;
376                         break;
377                     }
378 
379                     if ("com.fatwire.gst.foundation.url.WraPathAssembler".equals(classname)) {
380                         result = true;
381                     }
382 
383                     i++;
384                 }
385             } catch (IOException e) {
386                 LOG.error("Failure checking installer status: " + e, e);
387                 result = false;
388 
389             }
390             return result;
391         }
392 
393         @Override
394         public boolean install() {
395             LOG.info("Installing URL Assembler...");
396             try {
397                 String srProps = ctx.getRealPath("/WEB-INF/classes/ServletRequest.properties");
398                 InputStream in = new FileInputStream(srProps);
399                 Properties prop = new Properties();
400                 prop.load(in);
401                 in.close();
402                 int i = 1;
403                 boolean hasGSFAssembler = false;
404                 for (;;) {
405 
406                     String classname = prop.getProperty("uri.assembler." + i + ".classname");
407                     if (classname == null || classname.trim().length() == 0) {
408                         i--;
409                         break;
410                     }
411 
412                     if ("com.fatwire.gst.foundation.url.WraPathAssembler".equals(classname)) {
413                         hasGSFAssembler = true;
414                     }
415 
416                     i++;
417                 }
418 
419                 int max = i;
420                 if (!hasGSFAssembler) {
421                     for (i = max + 1; i > 1; i--) {
422                         String classname = prop.getProperty("uri.assembler." + (i - 1) + ".classname");
423                         String shortform = prop.getProperty("uri.assembler." + (i - 1) + ".shortform");
424                         prop.setProperty("uri.assembler." + i + ".classname", classname);
425                         prop.setProperty("uri.assembler." + i + ".shortform", shortform);
426                     }
427                     prop.setProperty("com.fatwire.gst.foundation.url.wrapathassembler.dispatcher", "GST/Dispatcher");
428                     prop.setProperty("uri.assembler.1.shortform", "wrapath");
429                     prop.setProperty("uri.assembler.1.classname", "com.fatwire.gst.foundation.url.WraPathAssembler");
430                     File orig = new File(srProps);
431                     File bk = new File(srProps + "." + System.currentTimeMillis() + ".bk");
432                     if (orig.exists()) {
433                         orig.renameTo(bk);
434                         FileOutputStream fout = new FileOutputStream(orig);
435                         prop.store(fout, "Modified by GSF installer.");
436                         fout.close();
437 
438                     }
439 
440                 }
441             } catch (IOException e) {
442                 LOG.error("Failure installing URL Assembler: " + e, e);
443             }
444             LOG.info("...URL Assembler installation complete.");
445             return true;
446         }
447 
448         @Override
449         public String getDescription() {
450             return "URL Assembler";
451         }
452 
453         public String getName() { return getClass().getSimpleName(); }
454     }
455 
456     class PageRefComponent implements GSFComponent {
457         @Override
458         public String getDescription() {
459             return "IPageReference component to build vanity urls";
460         }
461 
462         public String getName() { return getClass().getSimpleName(); }
463 
464         @Override
465         public boolean isInstalled() {
466 
467             try {
468                 String inipath = ctx.getInitParameter("inipath");
469 
470                 String srProps = Utilities.osSafeSpec(inipath + "/futuretense_xcel.ini");
471                 InputStream in = new FileInputStream(srProps);
472                 Properties prop = new Properties();
473                 prop.load(in);
474                 in.close();
475                 String pageref = prop.getProperty("xcelerate.pageref");
476                 if ("com.fatwire.gst.foundation.url.WraPageReference".equals(pageref)) {
477                     return true;
478                 }
479             } catch (IOException e) {
480                 LOG.error("Failure installing PageRef: " + e, e);
481             }
482             return false;
483         }
484 
485         @Override
486         public boolean install() {
487             LOG.info("Installing PageRef...");
488             try {
489                 String inipath = ctx.getInitParameter("inipath");
490 
491                 String srProps = Utilities.osSafeSpec(inipath + "/futuretense_xcel.ini");
492                 InputStream in = new FileInputStream(srProps);
493                 Properties prop = new Properties();
494                 prop.load(in);
495                 in.close();
496 
497                 // ics.StreamEvalBytes("Registring the GSF pageref in futuretense_xcel.ini.<br/>");
498                 prop.setProperty("xcelerate.pageref", "com.fatwire.gst.foundation.url.WraPageReference");
499                 File orig = new File(srProps);
500                 File bk = new File(srProps + "." + System.currentTimeMillis() + ".bk");
501                 if (orig.exists()) {
502                     orig.renameTo(bk);
503                     FileOutputStream fout = new FileOutputStream(orig);
504                     prop.store(fout, "Modified by GSF installer.");
505                     fout.close();
506                 }
507 
508             } catch (IOException e) {
509                 LOG.error("Failure installing PageRef: " + e, e);
510             }
511             LOG.info("...PageRef installation complete.");
512             return true;
513         }
514     }
515 
516     class UserInSiteComponent implements GSFComponent {
517         @Override
518         public String getDescription() {
519             return "User in site";
520         }
521 
522         public String getName() { return getClass().getSimpleName(); }
523 
524         @Override
525         public boolean isInstalled() {
526             UserManager um = getUserManager();
527             try {
528                 for (User u : um.read(Arrays.asList(ics.GetSSVar("username")))) {
529                     List<String> roles = u.getRoles("GST");
530                     if (roles == null)
531                         return false;
532                     if (roles.containsAll(Arrays.asList("GeneralAdmin", "AdvancedUser"))) {
533                         return true;
534                     } else {
535                         return false;
536                     }
537                 }
538                 return false;
539             } catch (SiteAccessException e) {
540                 LOG.error("Exception accessing user data for site: " + e, e);
541                 return false;
542             }
543         }
544 
545         /**
546          * @return
547          */
548         protected UserManager getUserManager() {
549             UserManager um = (UserManager) SessionFactory.getSession(ics).getManager(UserManager.class.getName());
550             return um;
551         }
552 
553         @Override
554         public boolean install() {
555             UserManager um = getUserManager();
556             List<User> us = new ArrayList<User>();
557             try {
558                 for (User u : um.read(Arrays.asList(ics.GetSSVar("username")))) {
559                     List<String> existingRoles = u.getRoles("GST");
560                     List<String> roles = Arrays.asList("AdvancedUser", "GeneralAdmin");
561                     roles.addAll(existingRoles);
562                     u.setRoles("GST", roles);
563                     us.add(u);
564                 }
565                 um.update(us);
566             } catch (SiteAccessException e) {
567                 LOG.error("Error adding user to site: " + e, e);
568             }
569             return true;
570         }
571     }
572 
573     /**
574      * Check if TreeTabs have GST site enabled or not. If tab is missing, that's
575      * ok (i.e. for Bookmarks or Active List tabs). If all TreeTabs have the GST
576      * site enabled, then return STATUS_OK. Otherwise return
577      * STATUS_NO_TREETABS_IN_SITE.
578      * 
579      * @return
580      */
581     class TreetabsInSiteComponent implements GSFComponent {
582         @Override
583         public String getDescription() {
584             return "TreeTabs";
585         }
586 
587         public String getName() { return getClass().getSimpleName(); }
588 
589         @Override
590         public boolean isInstalled() {
591             LOG.debug("Checking for GST Site TreeTabs");
592             FTValList list;
593             for (String t : GST_SITE_TREETABS) {
594                 LOG.debug("Checking if tab '" + t + "' is enabled for GST site.");
595                 // <TTM.LOAD OBJVARNAME="tab" NAME="GSTSiteTabs.ITEM" />
596                 // <TREETAB.GETID NAME="tab" VARNAME="tabid"/>
597                 // <TREETAB.GETSITES NAME="tab" OBJVARNAME="tsites"/>
598                 // <SITELIST.HASSITE NAME="tsites" PUBID="1328078963506"
599                 // VARNAME="hasSite"/>
600                 list = new FTValList();
601                 list.setValString("OBJVARNAME", "tab");
602                 list.setValString("NAME", t);
603                 ics.runTag("TTM.LOAD", list);
604 
605                 if (ics.GetErrno() == 0) {
606                     // Do we need to check for tab id here (to confirm it
607                     // exists)?
608                     ics.RemoveVar("tabid");
609                     list = new FTValList();
610                     list.setValString("NAME", "tab");
611                     list.setValString("VARNAME", "tabid");
612                     ics.runTag("TREETAB.GETID", list);
613                     if (Utilities.goodString(ics.GetVar("tabid"))) {
614                         LOG.debug("Tab '" + t + "' exists. Checking for GST site.");
615                         list = new FTValList();
616                         list.setValString("NAME", "tab");
617                         list.setValString("OBJVARNAME", "tsites");
618                         ics.runTag("TREETAB.GETSITES", list);
619                         list = new FTValList();
620                         list.setValString("NAME", "tsites");
621                         list.setValString("PUBID", ics.GetSSVar("pubid"));
622                         list.setValString("VARNAME", "hasSite");
623                         ics.runTag("SITELIST.HASSITE", list);
624                         if ("true".equals(ics.GetVar("hasSite"))) {
625                             LOG.debug("TreeTab '" + t + "' has GST site enabled.");
626                         } else {
627                             LOG.debug("TreeTab '" + t + "' exists but does NOT have GST site enabled.");
628                             return false;
629                         }
630                     }
631                 } else {
632                     LOG.debug("Unable to load TreeTab '" + t + "', skipping tab (this is OK). Errno="
633                             + ics.GetVar("errno"));
634                 }
635             }
636             LOG.debug("All TreeTabs checked have GST site enabled. Returning STATUS_OK.");
637             return true;
638         }
639 
640         @Override
641         public boolean install() {
642             LOG.info("Enabling TreeTabs for GST site.");
643             ics.CallElement("GST/Foundation/InstallTreeTabs", null);
644             LOG.info("Done enabling TreeTabs for GST site.");
645             return true;
646         }
647     }
648 
649     /**
650      * If CSElement and SiteEntry asset types are disabled in GST site, or if
651      * the GST/Dispatcher CSElement or SiteEntry is not shared with GST Site, or
652      * if their Start Menus don't exist for the GST site, then return status
653      * STATUS_CSE_SE_DISABLED_IN_SITE.
654      * 
655      * @return
656      */
657     class CSElementSiteEntryInSiteComponent implements GSFComponent {
658         @Override
659         public String getDescription() {
660             return "Startmenus and assettype enablement for CSElement and SiteEntry";
661         }
662 
663         public String getName() { return getClass().getSimpleName(); }
664 
665         @Override
666         public boolean isInstalled() {
667             LOG.debug("Starting checks for CSElement/SiteEntry.");
668             String[] assetTypes = { "CSElement", "SiteEntry" };
669             String[][] startMenuTypes = { { "ContentForm", "New " }, { "Search", "Find " } };
670             FTValList list;
671 
672             // check Start Menus
673             for (String at : assetTypes) {
674                 for (String[] sm : startMenuTypes) {
675                     LOG.debug("Doing Start Menu check for AssetType=" + at + ", StartMenu type=" + sm[0]);
676                     list = new FTValList();
677                     list.setValString("NAME", (sm[1] + at + ", GST"));
678                     list.setValString("ITEMTYPE", sm[0]);
679                     list.setValString("OBJVARNAME", "smTest");
680                     ics.runTag("STARTMENU.LOAD", list);
681                     LOG.debug("Start Menu loaded. Errno=" + ics.GetVar("errno"));
682                     list = new FTValList();
683                     list.setValString("NAME", "smTest");
684                     list.setValString("VARNAME", "smId");
685                     ics.runTag("STARTMENUITEM.GETID", list);
686                     if (Utilities.goodString(ics.GetVar("smId"))) {
687                         LOG.debug("StartMenu found for AssetType=" + at + ", StartMenu type=" + sm[0] + ", id="
688                                 + ics.GetVar("smId"));
689                         list = new FTValList();
690                         list.setValString("NAME", "smTest");
691                         list.setValString("OBJVARNAME", "smSiteList");
692                         ics.runTag("STARTMENUITEM.GETLEGALSITES", list);
693                         boolean hasSite = siteListHasSite("smSiteList", ics.GetSSVar("pubid"));
694                         if (hasSite) {
695                             LOG.debug("StartMenu '" + (sm[1] + at + ", GST") + "' has GST site enabled.");
696                         } else {
697                             LOG.debug("StartMenu '" + (sm[1] + at + ", GST")
698                                     + "' exists but does not have GST site enabled.");
699                             return false;
700                         }
701                     } else {
702                         LOG.debug("StartMenu not found for AssetType=" + at + ", StartMenu type=" + sm[0]);
703                         return false;
704                     }
705                 }
706             }
707 
708             // check if CSElement, SiteEntry Asset Types are enabled
709             LOG.debug("Done checking StartMenus. Checking if AssetTypes are enabled in GST site.");
710             for (String at : assetTypes) {
711                 FTValList args = new FTValList();
712                 args.setValString("upcommand", "IsAssetTypeEnabled");
713                 args.setValString("assettype", at);
714                 args.setValString("pubid", ics.GetSSVar("pubid"));
715                 ics.CallElement("OpenMarket/Xcelerate/Actions/AssetMgt/EnableAssetTypePub", args);
716                 if ("true".equals(ics.GetVar("IsAuthorized"))) {
717                     LOG.debug("GST Site is enabled for AssetType=" + at);
718                 } else {
719                     LOG.debug("GST Site is not enabled for AssetType=" + at + ", IsAuthorized="
720                             + ics.GetVar("IsAuthorized"));
721                     return false;
722                 }
723             }
724 
725             LOG.debug("Finished checks for CSElement/SiteEntry. Returning STATUS_OK.");
726             return true;
727         }
728 
729         @Override
730         public boolean install() {
731             LOG.info("Enabling TreeTabs for GST site.");
732             ics.CallElement("GST/Foundation/InstallCSElementSiteEntry", null);
733             LOG.info("Done enabling TreeTabs for GST site.");
734 
735             return true;
736         }
737     }
738 
739     /**
740      * Check if a CSElement and SiteEntry named "GST/Dispatcher" exist and are
741      * shared with the GST site.
742      * 
743      * @return
744      */
745     class GSTDispatcherComponent implements GSFComponent {
746         @Override
747         public String getDescription() {
748             return "Dispatcher element";
749         }
750 
751         public String getName() { return getClass().getSimpleName(); }
752 
753         @Override
754         public boolean isInstalled() {
755             String[] assetTypes = { "CSElement", "SiteEntry" };
756             for (String type : assetTypes) {
757                 LOG.debug("Checking if " + type + " 'GST/Dispatcher' exists.");
758 
759                 AssetId aid = AssetList.lookupAssetId(ics, type, "GST/Dispatcher");
760                 if (aid == null) {
761                     LOG.debug("Could not find " + type + " 'GST/Dispatcher'.");
762                     return false;
763                 }
764 
765                 LOG.debug("Found " + type + " 'GST/Dispatcher' with id=" + aid.getId()
766                         + ". Checking if it's shared with GST site (pubid " + ics.GetSSVar("pubid") + ")...");
767                 FTValList args = new FTValList();
768                 args.put("TYPE", type);
769                 args.put("OBJECTID", Long.toString(aid.getId()));
770                 args.put("LIST", "cseSiteList");
771                 args.put("PUBID", ics.GetSSVar("pubid"));
772                 ics.runTag("ASSET.SITES", args);
773                 if (Utilities.goodString(ics.GetVar("errno"))) {
774                     try {
775                         int errno = Integer.parseInt(ics.GetVar("errno"));
776                         if (errno >= 0) {
777                             LOG.debug(type + " GST/Dispatcher is enabled in the GST site.");
778                         } else {
779                             LOG.debug(type + " GST/Dispatcher is NOT enabled in the GST site. Errno="
780                                     + ics.GetVar("errno"));
781                             return false;
782                         }
783                     } catch (NumberFormatException e) {
784                         LOG.debug("Error parsing errno in GST/Dispatcher ASSET.SITES check.");
785                         return false;
786                     }
787                 } else {
788                     LOG.debug(type + " GST/Dispatcher is NOT enabled in the GST site.");
789                     return false;
790                 }
791             }
792 
793             return true;
794         }
795 
796         @Override
797         public boolean install() {
798             LOG.info("Creating GST/Dispatcher CSElement and SiteEntry");
799             ics.CallElement("GST/Foundation/InstallGSTDispatcher", null);
800             LOG.info("Done creating GST/Dispatcher CSElement and SiteEntry.");
801             return true;
802         }
803     }
804 
805     final boolean isInstallNeeded(int componentStatus, int systemStatus) {
806         return (systemStatus & componentStatus) == componentStatus;
807     }
808 
809     private void savePubid() {
810         String s = ics.GetSSVar("pubid");
811         if (StringUtils.isNotBlank(s)) {
812             ics.SetVar("oldpubid", s);
813             ics.RemoveSSVar("pubid");
814         }
815 
816         PublicationLoad load = new PublicationLoad();
817         load.setName("pubload");
818         load.setField("name");
819         load.setValue("GST");
820         load.execute(ics);
821         PublicationGet pGet = new PublicationGet();
822         pGet.setName("pubload");
823         pGet.setField("id");
824         pGet.setOutput("pubid");
825         pGet.execute(ics);
826         ics.SetSSVar("pubid", ics.GetVar("pubid"));
827     }
828 
829     private void restorePubid() {
830         String s = ics.GetVar("oldpubid");
831         if (StringUtils.isNotBlank(s)) {
832             ics.RemoveVar("oldpubid");
833             ics.SetSSVar("pubid", s);
834         }
835     }
836 
837     /**
838      * Checks if a SiteList contains the specified pubid
839      * 
840      * @param siteListObjName name of ICS object holiding the SiteList
841      * @param pubid pubid to check for
842      * @return true if SiteList contains the pubid specified by 'pubid'
843      */
844     private boolean siteListHasSite(String siteListObjName, String pubid) {
845         FTValList list = new FTValList();
846         list.setValString("NAME", siteListObjName);
847         list.setValString("PUBID", pubid);
848         list.setValString("VARNAME", "tempHasSiteCheck");
849         ics.runTag("SITELIST.HASSITE", list);
850         boolean hasSite = "true".equals(ics.GetVar("tempHasSiteCheck"));
851         ics.RemoveVar("tempHasSiteCheck");
852         return hasSite;
853     }
854 
855     // todo: check jstl core
856 }