0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/help/tags/sakai_2-4-1/help-component/src/java/org/sakaiproject/component/app/help/HelpManagerImpl.java $
0003: * $Id: HelpManagerImpl.java 15465 2006-09-30 14:38:36Z marquard@ched.uct.ac.za $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2003, 2004 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.component.app.help;
0021:
0022: import java.io.BufferedInputStream;
0023: import java.io.BufferedReader;
0024: import java.io.File;
0025: import java.io.IOException;
0026: import java.io.InputStreamReader;
0027: import java.io.Reader;
0028: import java.io.StringReader;
0029: import java.net.MalformedURLException;
0030: import java.net.URL;
0031: import java.net.URLConnection;
0032: import java.sql.SQLException;
0033: import java.util.ArrayList;
0034: import java.util.Collection;
0035: import java.util.Date;
0036: import java.util.HashMap;
0037: import java.util.HashSet;
0038: import java.util.Iterator;
0039: import java.util.List;
0040: import java.util.Map;
0041: import java.util.Set;
0042: import java.util.TreeSet;
0043:
0044: import javax.xml.parsers.DocumentBuilder;
0045: import javax.xml.parsers.DocumentBuilderFactory;
0046: import javax.xml.parsers.ParserConfigurationException;
0047:
0048: import org.hibernate.HibernateException;
0049: import org.hibernate.Session;
0050:
0051: import org.apache.commons.logging.Log;
0052: import org.apache.commons.logging.LogFactory;
0053: import org.apache.lucene.analysis.Analyzer;
0054: import org.apache.lucene.analysis.standard.StandardAnalyzer;
0055: import org.apache.lucene.document.Document;
0056: import org.apache.lucene.document.Field;
0057: import org.apache.lucene.index.IndexWriter;
0058: import org.apache.lucene.index.Term;
0059: import org.apache.lucene.queryParser.ParseException;
0060: import org.apache.lucene.queryParser.QueryParser;
0061: import org.apache.lucene.search.Hits;
0062: import org.apache.lucene.search.IndexSearcher;
0063: import org.apache.lucene.search.Query;
0064: import org.apache.lucene.search.Searcher;
0065: import org.apache.lucene.search.TermQuery;
0066: import org.sakaiproject.api.app.help.Category;
0067: import org.sakaiproject.api.app.help.Context;
0068: import org.sakaiproject.api.app.help.Glossary;
0069: import org.sakaiproject.api.app.help.GlossaryEntry;
0070: import org.sakaiproject.api.app.help.HelpManager;
0071: import org.sakaiproject.api.app.help.Resource;
0072: import org.sakaiproject.api.app.help.RestConfiguration;
0073: import org.sakaiproject.api.app.help.Source;
0074: import org.sakaiproject.api.app.help.TableOfContents;
0075: import org.sakaiproject.component.api.ServerConfigurationService;
0076: import org.sakaiproject.component.app.help.model.CategoryBean;
0077: import org.sakaiproject.component.app.help.model.ContextBean;
0078: import org.sakaiproject.component.app.help.model.ResourceBean;
0079: import org.sakaiproject.component.app.help.model.SourceBean;
0080: import org.sakaiproject.component.app.help.model.TableOfContentsBean;
0081: import org.sakaiproject.tool.api.Tool;
0082: import org.sakaiproject.tool.api.ToolManager;
0083: import org.springframework.beans.factory.BeanFactory;
0084: import org.springframework.beans.factory.xml.XmlBeanFactory;
0085: import org.springframework.core.io.InputStreamResource;
0086: import org.springframework.orm.hibernate3.HibernateCallback;
0087: import org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException;
0088: import org.springframework.orm.hibernate3.HibernateTransactionManager;
0089: import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
0090: import org.springframework.transaction.TransactionStatus;
0091: import org.springframework.transaction.support.TransactionCallback;
0092: import org.springframework.transaction.support.TransactionTemplate;
0093: import org.w3c.dom.NamedNodeMap;
0094: import org.w3c.dom.Node;
0095: import org.w3c.dom.NodeList;
0096: import org.xml.sax.InputSource;
0097: import org.xml.sax.SAXException;
0098:
0099: import sun.misc.BASE64Encoder;
0100:
0101: /**
0102: * HelpManager provides database and search capabilitites for the Sakai help tool.
0103: * @author <a href="mailto:jlannan.iupui.edu">Jarrod Lannan</a>
0104: * @version $Id: HelpManagerImpl.java 15465 2006-09-30 14:38:36Z marquard@ched.uct.ac.za $
0105: *
0106: */
0107: public class HelpManagerImpl extends HibernateDaoSupport implements
0108: HelpManager {
0109:
0110: private static final String QUERY_GETRESOURCEBYDOCID = "query.getResourceByDocId";
0111: private static final String QUERY_GETCATEGORYBYNAME = "query.getCategoryByName";
0112: private static final String QUERY_GET_WELCOME_PAGE = "query.getWelcomePage";
0113: private static final String DOCID = "docId";
0114: private static final String WELCOME_PAGE = "welcomePage";
0115: private static final String NAME = "name";
0116:
0117: private static final String LUCENE_INDEX_PATH = System
0118: .getProperty("java.io.tmpdir")
0119: + File.separator + "sakai.help";
0120:
0121: private static final String TOC_API = "org.sakaiproject.api.app.help.TableOfContents";
0122:
0123: private static String EXTERNAL_URL;
0124:
0125: private Map helpContextConfig = new HashMap();
0126: private int contextSize;
0127:
0128: private RestConfiguration restConfiguration;
0129: private ServerConfigurationService serverConfigurationService;
0130:
0131: private TableOfContentsBean toc;
0132: private Boolean initialized = Boolean.FALSE;
0133:
0134: private Glossary glossary;
0135: private String supportEmailAddress;
0136:
0137: private ToolManager toolManager;
0138: private HibernateTransactionManager txManager;
0139:
0140: Set allCategories = new TreeSet();
0141:
0142: private static final Log LOG = LogFactory
0143: .getLog(HelpManagerImpl.class);
0144:
0145: /**
0146: * @see org.sakaiproject.api.app.help.HelpManager#getServerConfigurationService()
0147: */
0148: public ServerConfigurationService getServerConfigurationService() {
0149: return serverConfigurationService;
0150: }
0151:
0152: /**
0153: * @see org.sakaiproject.api.app.help.HelpManager#setServerConfigurationService(org.sakaiproject.service.framework.config.ServerConfigurationService)
0154: */
0155: public void setServerConfigurationService(
0156: ServerConfigurationService s) {
0157: serverConfigurationService = s;
0158: }
0159:
0160: public List getContexts(String mappedView) {
0161: return (List) helpContextConfig.get(mappedView);
0162: }
0163:
0164: public List getActiveContexts(Map session) {
0165: List contexts = (List) session.get("help_contexts");
0166: if (contexts == null) {
0167: contexts = new SizedList(getContextSize());
0168: session.put("help_contexts", contexts);
0169: }
0170: return contexts;
0171: }
0172:
0173: public void addContexts(Map session, String mappedView) {
0174: List newContexts = getContexts(mappedView);
0175: List contexts = getActiveContexts(session);
0176: if (newContexts != null) {
0177: contexts.addAll(newContexts);
0178: }
0179: }
0180:
0181: /**
0182: * return list of resources matching context id
0183: *
0184: * @param contextId
0185: * @return
0186: */
0187: public Set getResources(Long contextId) {
0188: ContextBean context = (ContextBean) getContext(contextId);
0189: return searchResources(new TermQuery(new Term("context", "\""
0190: + contextId + "\"")));
0191: }
0192:
0193: /**
0194: * Store resource
0195: * @see org.sakaiproject.api.app.help.HelpManager#storeResource(org.sakaiproject.api.help.Entity)
0196: */
0197: public void storeResource(Resource resource) {
0198: getHibernateTemplate().saveOrUpdate(resource);
0199: }
0200:
0201: /**
0202: * @see org.sakaiproject.api.app.help.HelpManager#getResource(java.lang.Long)
0203: */
0204: public Resource getResource(Long id) {
0205: return (ResourceBean) getHibernateTemplate().get(
0206: ResourceBean.class, id);
0207: }
0208:
0209: /**
0210: * @see org.sakaiproject.api.app.help.HelpManager#deleteResource(java.lang.Long)
0211: */
0212: public void deleteResource(Long resourceId) {
0213: Resource resource = getResource(resourceId);
0214: if (resource == null)
0215: return;
0216: getHibernateTemplate().delete(resource);
0217: }
0218:
0219: /**
0220: * @see org.sakaiproject.api.app.help.HelpManager#getSource(java.lang.Long)
0221: */
0222: public Source getSource(Long id) {
0223: try {
0224: return (SourceBean) getHibernateTemplate().load(
0225: SourceBean.class, id);
0226: } catch (HibernateObjectRetrievalFailureException e) {
0227: return null;
0228: }
0229: }
0230:
0231: /**
0232: * @see org.sakaiproject.api.app.help.HelpManager#storeSource(org.sakaiproject.api.help.Source)
0233: */
0234: public void storeSource(Source source) {
0235: getHibernateTemplate().saveOrUpdate(source);
0236: }
0237:
0238: /**
0239: * @see org.sakaiproject.api.app.help.HelpManager#deleteSource(java.lang.Long)
0240: */
0241: public void deleteSource(Long sourceId) {
0242: Source source = getSource(sourceId);
0243: if (source == null)
0244: return;
0245: getHibernateTemplate().delete(source);
0246: }
0247:
0248: /**
0249: * @see org.sakaiproject.api.app.help.HelpManager#getContext(java.lang.Long)
0250: */
0251: public Context getContext(Long id) {
0252: try {
0253: return (ContextBean) getHibernateTemplate().load(
0254: ContextBean.class, id);
0255: } catch (HibernateObjectRetrievalFailureException e) {
0256: return null;
0257: }
0258: }
0259:
0260: /**
0261: * @see org.sakaiproject.api.app.help.HelpManager#storeContext(org.sakaiproject.api.help.Context)
0262: */
0263: public void storeContext(Context context) {
0264: getHibernateTemplate().saveOrUpdate(context);
0265: }
0266:
0267: /**
0268: * @see org.sakaiproject.api.app.help.HelpManager#deleteContext(java.lang.Long)
0269: */
0270: public void deleteContext(Long contextId) {
0271: Context context = getContext(contextId);
0272: if (context == null)
0273: return;
0274: getHibernateTemplate().delete(context);
0275: }
0276:
0277: /**
0278: * @see org.sakaiproject.api.app.help.HelpManager#getResourcesForActiveContexts(java.util.Map)
0279: */
0280: public Map getResourcesForActiveContexts(Map session) {
0281: Map resourceMap = new HashMap();
0282: List activeContexts = getActiveContexts(session);
0283: for (Iterator i = activeContexts.iterator(); i.hasNext();) {
0284: String context = (String) i.next();
0285: try {
0286: Set resources = searchResources(new TermQuery(new Term(
0287: "context", "\"" + context + "\"")));
0288: if (resources != null && resources.size() > 0) {
0289: resourceMap.put(context, resources);
0290: }
0291: } catch (Exception e) {
0292: LOG.error(e);
0293: }
0294: }
0295: return resourceMap;
0296: }
0297:
0298: /**
0299: * @see org.sakaiproject.api.app.help.HelpManager#searchResources(java.lang.String)
0300: */
0301: public Set searchResources(String queryStr) {
0302: initialize();
0303:
0304: try {
0305: return searchResources(queryStr, "content");
0306: } catch (ParseException e) {
0307: LOG.debug("ParseException parsing Help search query "
0308: + queryStr);
0309: return null;
0310: }
0311: }
0312:
0313: /**
0314: * @see org.sakaiproject.api.app.help.HelpManager#getTableOfContents()
0315: */
0316: public TableOfContents getTableOfContents() {
0317: initialize();
0318: return getToc();
0319: }
0320:
0321: /**
0322: * @see org.sakaiproject.api.app.help.HelpManager#setTableOfContents(org.sakaiproject.api.help.TableOfContents)
0323: */
0324: public void setTableOfContents(TableOfContents toc) {
0325: setToc((TableOfContentsBean) toc);
0326: }
0327:
0328: /**
0329: * @see org.sakaiproject.api.app.help.HelpManager#searchGlossary(java.lang.String)
0330: */
0331: public GlossaryEntry searchGlossary(String keyword) {
0332: return getGlossary().find(keyword);
0333: }
0334:
0335: /**
0336: * Search Resources
0337: * @param query
0338: * @return Set of matching results.
0339: */
0340: protected Set searchResources(Query query) {
0341: Set results = new HashSet();
0342: try {
0343: Searcher searcher = new IndexSearcher(LUCENE_INDEX_PATH);
0344: LOG.debug("Searching for: " + query.toString());
0345:
0346: Hits hits = searcher.search(query);
0347: LOG.debug(hits.length() + " total matching documents");
0348:
0349: for (int i = 0; i < hits.length(); i++) {
0350: ResourceBean resource = getResourceFromDocument(hits
0351: .doc(i));
0352: resource.setScore(hits.score(i) * 100);
0353: results.add(resource);
0354: }
0355: searcher.close();
0356: } catch (Exception e) {
0357: LOG.error(e);
0358: }
0359: return results;
0360: }
0361:
0362: /**
0363: * Search Lucene
0364: *
0365: * @param queryStr
0366: * @param defaultField
0367: * @return
0368: * @throws ParseException
0369: */
0370: protected Set searchResources(String queryStr, String defaultField)
0371: throws ParseException {
0372: Analyzer analyzer = new StandardAnalyzer();
0373: Query query = QueryParser.parse(queryStr, defaultField,
0374: analyzer);
0375: return searchResources(query);
0376: }
0377:
0378: /**
0379: * Get Resource From Document.
0380: * @param document
0381: * @return resource bean
0382: */
0383: protected ResourceBean getResourceFromDocument(Document document) {
0384: Long id = new Long(document.getField("id").stringValue());
0385: return (ResourceBean) getResource(id);
0386: }
0387:
0388: /**
0389: * Get entire Collection of Resources.
0390: * @return collection of resources
0391: */
0392: protected Collection getResources() {
0393: return getHibernateTemplate().loadAll(ResourceBean.class);
0394: }
0395:
0396: /**
0397: * Get ContextSize.
0398: * @return size of Context.
0399: */
0400: public int getContextSize() {
0401: return contextSize;
0402: }
0403:
0404: /**
0405: * Set ContextSize
0406: * @param contextSize
0407: */
0408: public void setContextSize(int contextSize) {
0409: this .contextSize = contextSize;
0410: }
0411:
0412: /**
0413: * Get Document.
0414: * @param resource
0415: * @return document
0416: * @throws IOException
0417: * @throws MalformedURLException
0418: */
0419: protected Document getDocument(ResourceBean resource)
0420: throws IOException, MalformedURLException {
0421:
0422: Document doc = new Document();
0423:
0424: if (resource.getContexts() != null) {
0425: for (Iterator i = resource.getContexts().iterator(); i
0426: .hasNext();) {
0427: doc.add(Field.Keyword("context", "\""
0428: + ((String) i.next()) + "\""));
0429: }
0430: }
0431:
0432: URL urlResource;
0433: URLConnection urlConnection = null;
0434: StringBuffer sBuffer = new StringBuffer();
0435: if (resource.getLocation() == null
0436: || resource.getLocation().startsWith("/")) {
0437: // handle REST content
0438: if (!getRestConfiguration().getOrganization().equals(
0439: "sakai")) {
0440: urlResource = new URL(getRestConfiguration()
0441: .getRestUrlInDomain()
0442: + resource.getDocId()
0443: + "?domain="
0444: + getRestConfiguration().getRestDomain());
0445: urlConnection = urlResource.openConnection();
0446:
0447: String basicAuthUserPass = getRestConfiguration()
0448: .getRestCredentials();
0449: String encoding = new BASE64Encoder()
0450: .encode(basicAuthUserPass.getBytes());
0451:
0452: urlConnection.setRequestProperty("Authorization",
0453: "Basic " + encoding);
0454:
0455: sBuffer = new StringBuffer();
0456:
0457: BufferedReader br = new BufferedReader(
0458: new InputStreamReader(urlConnection
0459: .getInputStream()), 512);
0460: int readReturn = 0;
0461: char[] cbuf = new char[512];
0462: while ((readReturn = br.read(cbuf, 0, 512)) != -1) {
0463: sBuffer.append(cbuf, 0, readReturn);
0464: }
0465:
0466: // if document is coming from corpus then get document name from xml and assign to resource
0467: String resourceName = getRestConfiguration()
0468: .getResourceNameFromCorpusDoc(
0469: sBuffer.toString());
0470: resource.setName(resourceName);
0471: storeResource(resource);
0472:
0473: } else if (!"".equals(EXTERNAL_URL)) {
0474: // handle external help location
0475: urlResource = new URL(EXTERNAL_URL
0476: + resource.getLocation());
0477: } else {
0478: // handle classpath location
0479: urlResource = getClass().getResource(
0480: resource.getLocation());
0481: }
0482: } else {
0483: // handle external location specified in reg file
0484: urlResource = new URL(resource.getLocation());
0485: }
0486:
0487: if (urlResource == null) {
0488: return null;
0489: }
0490:
0491: if (resource.getLocation() != null) {
0492: doc.add(Field.Keyword("location", resource.getLocation()));
0493: }
0494:
0495: //doc.add(Field.Keyword("name", resource.getName()));
0496: doc.add(Field.Keyword("id", resource.getId().toString()));
0497:
0498: if (getRestConfiguration().getOrganization().equals("sakai")) {
0499: Reader reader = new BufferedReader(new InputStreamReader(
0500: urlResource.openStream()));
0501:
0502: int readReturn = 0;
0503: char[] cbuf = new char[512];
0504: while ((readReturn = reader.read(cbuf, 0, 512)) != -1) {
0505: sBuffer.append(cbuf, 0, readReturn);
0506: }
0507:
0508: doc.add(Field.Text("content", sBuffer.toString()));
0509: } else {
0510: doc.add(Field.Text("content", sBuffer.toString()));
0511: }
0512:
0513: return doc;
0514: }
0515:
0516: /**
0517: * Get Table Of Contents Bean.
0518: * @return table of contents bean
0519: */
0520: public TableOfContentsBean getToc() {
0521: if (toc == null) {
0522: toc = new TableOfContentsBean();
0523: //Collection categories = getHibernateTemplate()
0524: // .loadAll(CategoryBean.class);
0525: toc.setCategories(allCategories);
0526:
0527: }
0528: return toc;
0529: }
0530:
0531: /**
0532: * Set Table Of Contents Bean.
0533: * @param toc
0534: */
0535: public void setToc(TableOfContentsBean toc) {
0536: this .toc = toc;
0537: }
0538:
0539: /**
0540: * @see org.sakaiproject.api.app.help.HelpManager#getGlossary()
0541: */
0542: public Glossary getGlossary() {
0543: return glossary;
0544: }
0545:
0546: /**
0547: * Set Glossary.
0548: * @param glossary
0549: */
0550: public void setGlossary(Glossary glossary) {
0551: this .glossary = glossary;
0552: }
0553:
0554: /**
0555: * @see org.sakaiproject.api.app.help.HelpManager#storeCategory(org.sakaiproject.api.help.Category)
0556: */
0557: public void storeCategory(Category category) {
0558: getHibernateTemplate().saveOrUpdate(category);
0559: }
0560:
0561: /**
0562: * @see org.sakaiproject.api.app.help.HelpManager#createCategory()
0563: */
0564: public Category createCategory() {
0565: return new CategoryBean();
0566: }
0567:
0568: /**
0569: * @see org.sakaiproject.api.app.help.HelpManager#createResource()
0570: */
0571: public Resource createResource() {
0572: return new ResourceBean();
0573: }
0574:
0575: /**
0576: * @see org.sakaiproject.api.app.help.HelpManager#getResourceByDocId(java.lang.String)
0577: */
0578: public Resource getResourceByDocId(final String docId) {
0579: HibernateCallback hcb = new HibernateCallback() {
0580: public Object doInHibernate(Session session)
0581: throws HibernateException, SQLException {
0582: org.hibernate.Query q = session
0583: .getNamedQuery(QUERY_GETRESOURCEBYDOCID);
0584:
0585: q.setString(DOCID, (docId == null) ? null : docId
0586: .toLowerCase());
0587: if (q.list().size() == 0) {
0588: return null;
0589: } else {
0590: return (Resource) q.list().get(0);
0591: }
0592: }
0593: };
0594: Resource resource = (Resource) getHibernateTemplate().execute(
0595: hcb);
0596: return resource;
0597: }
0598:
0599: /**
0600: * @see org.sakaiproject.api.app.help.HelpManager#getWelcomePage()
0601: */
0602: public String getWelcomePage() {
0603: initialize();
0604: HibernateCallback hcb = new HibernateCallback() {
0605: public Object doInHibernate(Session session)
0606: throws HibernateException, SQLException {
0607: org.hibernate.Query q = session
0608: .getNamedQuery(QUERY_GET_WELCOME_PAGE);
0609: q.setString(WELCOME_PAGE, "true");
0610: if (q.list().size() == 0) {
0611: return null;
0612: } else {
0613: return ((Resource) q.list().get(0)).getDocId();
0614: }
0615: }
0616: };
0617: return (String) getHibernateTemplate().execute(hcb);
0618: }
0619:
0620: /**
0621: * Find a Category by name
0622: * @param name
0623: * @return Category
0624: */
0625: public Category getCategoryByName(final String name) {
0626: HibernateCallback hcb = new HibernateCallback() {
0627: public Object doInHibernate(Session session)
0628: throws HibernateException, SQLException {
0629: org.hibernate.Query q = session
0630: .getNamedQuery(QUERY_GETCATEGORYBYNAME);
0631: q.setString(NAME, (name == null) ? name : name
0632: .toLowerCase());
0633: return q.uniqueResult();
0634: }
0635: };
0636: return (Category) getHibernateTemplate().execute(hcb);
0637: }
0638:
0639: /**
0640: * Store the mapping of Categories and Resources
0641: * @param categories
0642: */
0643: private void storeRecursive(Set categories) {
0644: Iterator i = categories.iterator();
0645: while (i.hasNext()) {
0646: Category category = (Category) i.next();
0647:
0648: Set resourcesList = category.getResources();
0649: category.setResources(null);
0650:
0651: for (Iterator resourceIterator = resourcesList.iterator(); resourceIterator
0652: .hasNext();) {
0653: Resource resource = (Resource) resourceIterator.next();
0654: resource.setCategory(category);
0655: }
0656:
0657: category.setResources(resourcesList);
0658: this .storeCategory(category);
0659:
0660: Set subCategories = category.getCategories();
0661: storeRecursive(subCategories);
0662: }
0663: }
0664:
0665: /**
0666: * Get Support Email Address.
0667: * @see org.sakaiproject.api.app.help.HelpManager#getSupportEmailAddress()
0668: */
0669: public String getSupportEmailAddress() {
0670: return supportEmailAddress;
0671: }
0672:
0673: /**
0674: * set Support Email Address.
0675: * @param email
0676: */
0677: public void setSupportEmailAddress(String email) {
0678: this .supportEmailAddress = email;
0679: }
0680:
0681: /**
0682: * get tool manager
0683: * @return Returns the toolManager.
0684: */
0685: public ToolManager getToolManager() {
0686: return toolManager;
0687: }
0688:
0689: /**
0690: * set tool manager
0691: * @param toolManager The toolManager to set.
0692: */
0693: public void setToolManager(ToolManager toolManager) {
0694: this .toolManager = toolManager;
0695: }
0696:
0697: /**
0698: * @param txManager The txManager to set.
0699: */
0700: public void setTxManager(HibernateTransactionManager txManager) {
0701: this .txManager = txManager;
0702: }
0703:
0704: /**
0705: * @see org.sakaiproject.api.app.help.HelpManager#getRestConfiguration()
0706: */
0707: public RestConfiguration getRestConfiguration() {
0708: return restConfiguration;
0709: }
0710:
0711: /**
0712: * set REST configuration
0713: * @param restConfiguration
0714: */
0715: public void setRestConfiguration(RestConfiguration restConfiguration) {
0716: this .restConfiguration = restConfiguration;
0717: }
0718:
0719: /**
0720: * Reinitialize help content from UI
0721: */
0722: public void reInitialize() {
0723: initialized = Boolean.FALSE;
0724: initialize();
0725: }
0726:
0727: /**
0728: * Synchronize first access to tool.
0729: * @see org.sakaiproject.api.app.help.HelpManager#initialize()
0730: */
0731: public void initialize() {
0732: if (initialized.booleanValue()) {
0733: return;
0734: } else {
0735: synchronized (initialized) {
0736: if (!initialized.booleanValue()) {
0737: dropExistingContent();
0738:
0739: // handle external help content
0740: EXTERNAL_URL = getServerConfigurationService()
0741: .getString("help.location");
0742: if (!"".equals(EXTERNAL_URL)) {
0743: if (EXTERNAL_URL.endsWith("/")) {
0744: // remove trailing forward slash
0745: EXTERNAL_URL = EXTERNAL_URL.substring(0,
0746: EXTERNAL_URL.length() - 1);
0747: }
0748: }
0749:
0750: registerHelpContent();
0751: initialized = Boolean.TRUE;
0752: }
0753: }
0754: }
0755: }
0756:
0757: /**
0758: * @see org.sakaiproject.api.app.help.HelpManager#getExternalLocation()
0759: */
0760: public String getExternalLocation() {
0761: return EXTERNAL_URL;
0762: }
0763:
0764: private void dropExistingContent() {
0765: if (LOG.isDebugEnabled()) {
0766: LOG.debug("dropExistingContent()");
0767: }
0768:
0769: TransactionTemplate tt = new TransactionTemplate(txManager);
0770: tt.execute(new TransactionCallback() {
0771: public Object doInTransaction(TransactionStatus status) {
0772: getHibernateTemplate()
0773: .bulkUpdate("delete CategoryBean");
0774: getHibernateTemplate().flush();
0775: return null;
0776: }
0777: });
0778: }
0779:
0780: /**
0781: * Register help content either locally or externally
0782: * Index resources in Lucene
0783: */
0784: private void registerHelpContent() {
0785: if (LOG.isDebugEnabled()) {
0786: LOG.debug("registerHelpContent()");
0787: }
0788:
0789: // register external help docs
0790: if (!"".equals(EXTERNAL_URL)) {
0791: registerExternalHelpContent(EXTERNAL_URL + "/help.xml");
0792: } else {
0793: registerStaticContent();
0794: }
0795:
0796: // create index in lucene
0797: IndexWriter writer = null;
0798: Date start = new Date();
0799: try {
0800: writer = new IndexWriter(LUCENE_INDEX_PATH,
0801: new StandardAnalyzer(), true);
0802: } catch (IOException e) {
0803: LOG.error("failed to create IndexWriter " + e.getMessage());
0804: }
0805:
0806: for (Iterator i = getResources().iterator(); i.hasNext();) {
0807: ResourceBean resource = (ResourceBean) i.next();
0808:
0809: try {
0810: Document doc = getDocument(resource);
0811: if (doc != null) {
0812: writer.addDocument(doc);
0813: LOG.info("added resource '" + resource.getName()
0814: + "', doc count=" + writer.docCount());
0815: } else {
0816: LOG.debug("failed to add resource '" + "' ("
0817: + resource.getName());
0818: }
0819: } catch (IOException e) {
0820: LOG.error("I/O error while adding resource '" + "' ("
0821: + resource.getName() + "): " + e.getMessage());
0822: }
0823: }
0824: try {
0825: writer.optimize();
0826: writer.close();
0827: } catch (IOException e) {
0828: LOG.error("failed to close writer " + e.getMessage());
0829: }
0830:
0831: Date end = new Date();
0832: LOG.info("finished initializing lucene in "
0833: + (end.getTime() - start.getTime())
0834: + " total milliseconds");
0835: }
0836:
0837: /**
0838: * register external help content
0839: * build document from external reg file
0840: * @param externalHelpReg
0841: */
0842: public void registerExternalHelpContent(String externalHelpReg) {
0843:
0844: BufferedInputStream bis = null;
0845: BufferedInputStream bisCorpus = null;
0846: try {
0847: URL urlResource = new URL(externalHelpReg);
0848: bis = new BufferedInputStream(urlResource.openStream());
0849:
0850: DocumentBuilderFactory dbf = DocumentBuilderFactory
0851: .newInstance();
0852: dbf.setNamespaceAware(true);
0853: DocumentBuilder builder = dbf.newDocumentBuilder();
0854:
0855: InputSource is = new org.xml.sax.InputSource(bis);
0856: org.w3c.dom.Document xmlDocument = builder.parse(is);
0857:
0858: Node helpRegNode = (Node) xmlDocument.getDocumentElement();
0859: recursiveExternalReg(helpRegNode, null);
0860:
0861: // handle corpus docs
0862: if (!getRestConfiguration().getOrganization().equals(
0863: "sakai")) {
0864:
0865: // get corpus document
0866: String corpusXml = getRestConfiguration()
0867: .getCorpusDocument();
0868: DocumentBuilderFactory dbfCorpus = DocumentBuilderFactory
0869: .newInstance();
0870: dbfCorpus.setNamespaceAware(true);
0871: DocumentBuilder builderCorpus = dbfCorpus
0872: .newDocumentBuilder();
0873: StringReader sReader = new StringReader(corpusXml);
0874: InputSource isCorpus = new org.xml.sax.InputSource(
0875: sReader);
0876: org.w3c.dom.Document xmlDocumentCorpus = builderCorpus
0877: .parse(isCorpus);
0878:
0879: registerCorpusDocs(xmlDocumentCorpus);
0880: sReader.close();
0881: }
0882:
0883: } catch (MalformedURLException e) {
0884: LOG.warn("Unable to load external URL: " + EXTERNAL_URL
0885: + "/help.xml", e);
0886: } catch (IOException e) {
0887: LOG.warn("I/O error opening external URL: " + EXTERNAL_URL
0888: + "/help.xml", e);
0889: } catch (ParserConfigurationException e) {
0890: LOG.error(e.getMessage(), e);
0891: } catch (SAXException e) {
0892: LOG.error(e.getMessage(), e);
0893: } finally {
0894: try {
0895: if (bis != null) {
0896: bis.close();
0897: }
0898: if (bisCorpus != null) {
0899: bisCorpus.close();
0900: }
0901: } catch (IOException e) {
0902: LOG.error("error closing stream", e);
0903: }
0904: }
0905: }
0906:
0907: /**
0908: * register local content
0909: */
0910: public void registerStaticContent() {
0911: // register static content
0912: Set toolSet = toolManager.findTools(null, null);
0913: List helpClasspathRegList = new ArrayList();
0914:
0915: for (Iterator i = toolSet.iterator(); i.hasNext();) {
0916: Tool tool = (Tool) i.next();
0917: if (tool != null && tool.getId() != null) {
0918: helpClasspathRegList.add("/"
0919: + tool.getId().toLowerCase().replaceAll("\\.",
0920: "_") + "/" + "help.xml");
0921: }
0922: }
0923:
0924: // add non-standard ids (generic help topics rather than tool help)
0925: helpClasspathRegList.add("/sakai_iframe_myworkspace/help.xml");
0926: helpClasspathRegList.add("/sakai_menubar/help.xml");
0927: helpClasspathRegList.add("/sakai_course_sites/help.xml");
0928: helpClasspathRegList.add("/sakai_permissions/help.xml");
0929: helpClasspathRegList.add("/sakai_accessibility/help.xml");
0930:
0931: //Set allCategories = new TreeSet();
0932:
0933: for (Iterator i = helpClasspathRegList.iterator(); i.hasNext();) {
0934: String classpathUrl = (String) i.next();
0935:
0936: URL urlResource = null;
0937:
0938: if (!"".equals(EXTERNAL_URL)) {
0939: // handle external help location
0940: try {
0941: urlResource = new URL(EXTERNAL_URL + classpathUrl);
0942: } catch (MalformedURLException e) {
0943: LOG.debug("Unable to load external URL: "
0944: + classpathUrl);
0945: continue;
0946: }
0947: } else {
0948: urlResource = getClass().getResource(classpathUrl);
0949:
0950: if (urlResource == null) {
0951: LOG.debug("Unable to load resource: "
0952: + classpathUrl);
0953: continue;
0954: }
0955: }
0956:
0957: if (urlResource == null) {
0958: LOG.debug("Unable to load classpath resource: "
0959: + classpathUrl);
0960: continue;
0961: }
0962: try {
0963: org.springframework.core.io.Resource resource = new InputStreamResource(
0964: urlResource.openStream(), classpathUrl);
0965: BeanFactory beanFactory = new XmlBeanFactory(resource);
0966: TableOfContents tocTemp = (TableOfContents) beanFactory
0967: .getBean(TOC_API);
0968: Set categories = tocTemp.getCategories();
0969:
0970: storeRecursive(categories);
0971: allCategories.addAll(categories);
0972: } catch (Exception e) {
0973: LOG.debug("Unable to load classpath resource: "
0974: + classpathUrl);
0975: }
0976: }
0977:
0978: toc = new TableOfContentsBean();
0979: toc.setCategories(allCategories);
0980:
0981: }
0982:
0983: private static int cnt = 0;
0984:
0985: /**
0986: * Parse external help reg doc recursively
0987: * @param n
0988: * @param category
0989: */
0990: public void recursiveExternalReg(Node n, Category category) {
0991:
0992: if (n == null) {
0993: return;
0994: }
0995:
0996: NodeList nodeList = n.getChildNodes();
0997: int nodeListLength = nodeList.getLength();
0998:
0999: for (int i = 0; i < nodeListLength; i++) {
1000: if (nodeList.item(i).getNodeType() != Node.ELEMENT_NODE) {
1001: continue;
1002: }
1003:
1004: Node currentNode = nodeList.item(i);
1005:
1006: if ("category".equals(currentNode.getNodeName())) {
1007: Category childCategory = new CategoryBean();
1008: childCategory.setName(currentNode.getAttributes()
1009: .getNamedItem("name").getNodeValue());
1010:
1011: if (category != null) {
1012: childCategory.setParent(category);
1013: category.getCategories().add(childCategory);
1014: }
1015:
1016: storeCategory(childCategory);
1017: allCategories.add(childCategory);
1018:
1019: LOG.info("adding help category: "
1020: + childCategory.getName());
1021:
1022: recursiveExternalReg(currentNode, childCategory);
1023: } else if ("resource".equals(currentNode.getNodeName())) {
1024: Resource resource = new ResourceBean();
1025: NamedNodeMap nnm = currentNode.getAttributes();
1026:
1027: if (nnm != null) {
1028: // name required
1029: resource.setName(nnm.getNamedItem("name")
1030: .getNodeValue());
1031:
1032: if (nnm.getNamedItem("location") != null) {
1033: resource.setLocation(nnm.getNamedItem(
1034: "location").getNodeValue());
1035: }
1036:
1037: if (nnm.getNamedItem("docId") != null) {
1038: resource.setDocId(nnm.getNamedItem("docId")
1039: .getNodeValue());
1040: } else {
1041: resource.setDocId(new Integer(cnt).toString());
1042: cnt++;
1043: }
1044:
1045: //defaultForTool is an optional attribute
1046: if (nnm.getNamedItem("defaultForTool") != null) {
1047: resource.setDefaultForTool(nnm.getNamedItem(
1048: "defaultForTool").getNodeValue());
1049: }
1050:
1051: // welcomePage is an optional attribute
1052: if (nnm.getNamedItem("welcomePage") != null) {
1053: resource.setWelcomePage(nnm.getNamedItem(
1054: "welcomePage").getNodeValue()
1055: .toLowerCase());
1056: }
1057: }
1058:
1059: resource.setCategory(category);
1060: category.getResources().add(resource);
1061: storeResource(resource);
1062:
1063: LOG.info("adding help resource: " + resource
1064: + " to category: " + category.getName());
1065: recursiveExternalReg(currentNode, category);
1066: }
1067: }
1068:
1069: }
1070:
1071: /**
1072: * Parse corpus document
1073: * @param doc document
1074: */
1075: public void registerCorpusDocs(org.w3c.dom.Document doc) {
1076: if (doc == null)
1077: return;
1078:
1079: List arrayCorpus = new ArrayList();
1080:
1081: NodeList nodeList = doc.getElementsByTagName("id");
1082: int nodeListLength = nodeList.getLength();
1083:
1084: for (int i = 0; i < nodeListLength; i++) {
1085: Node currentNode = nodeList.item(i);
1086: NodeList nlChildren = currentNode.getChildNodes();
1087:
1088: for (int j = 0; j < nlChildren.getLength(); j++) {
1089: if (nlChildren.item(j).getNodeType() == Node.TEXT_NODE) {
1090: arrayCorpus.add(nlChildren.item(j).getNodeValue());
1091: }
1092: }
1093: }
1094:
1095: // iterate through corpus docs and add to home category if not already
1096: // added by help.xml external registration
1097:
1098: // if Home category does not exist, then create it
1099: if (getCategoryByName("Home") == null) {
1100: Category cat = new CategoryBean();
1101: cat.setName("Home");
1102: storeCategory(cat);
1103: }
1104:
1105: for (int i = 0; i < arrayCorpus.size(); i++) {
1106: String currentDocId = (String) arrayCorpus.get(i);
1107:
1108: // if the corpus doc does not already exist from help.xml, then add it to the Home category
1109: if (this .getResourceByDocId(currentDocId) == null) {
1110: Resource resource = new ResourceBean();
1111: resource.setDocId(currentDocId);
1112: resource.setName(currentDocId);
1113: Category homeCategory = getCategoryByName("Home");
1114: resource.setCategory(homeCategory);
1115: homeCategory.getResources().add(resource);
1116: storeResource(resource);
1117: }
1118: }
1119: }
1120:
1121: }
|