1 16 package org.outerj.daisy.books.publisher.impl; 17 18 import org.outerj.daisy.books.publisher.BookPublisher; 19 import org.outerj.daisy.books.publisher.PublicationSpec; 20 import org.outerj.daisy.books.publisher.PublicationTypeInfo; 21 import org.outerj.daisy.books.publisher.PublishTaskInfo; 22 import org.outerj.daisy.books.publisher.impl.publicationtype.PublicationTypeBuilder; 23 import org.outerj.daisy.books.store.BookStore; 24 import org.outerj.daisy.books.store.BookInstance; 25 import org.outerj.daisy.books.store.BookAcl; 26 import org.outerj.daisy.books.store.impl.BookAclEvaluator; 27 import org.outerj.daisy.books.store.impl.AclResult; 28 import org.outerj.daisy.frontend.components.wikidatasource.WikiDataSource; 29 import org.outerj.daisy.repository.Repository; 30 import org.outerj.daisy.repository.VariantKey; 31 import org.outerj.daisy.repository.clientimpl.RemoteRepositoryImpl; 32 import org.outerj.daisy.xmlutil.LocalSAXParserFactory; 33 import org.apache.avalon.framework.service.Serviceable; 34 import org.apache.avalon.framework.service.ServiceManager; 35 import org.apache.avalon.framework.service.ServiceException; 36 import org.apache.avalon.framework.context.Contextualizable; 37 import org.apache.avalon.framework.context.Context; 38 import org.apache.avalon.framework.context.ContextException; 39 import org.apache.avalon.framework.thread.ThreadSafe; 40 import org.apache.avalon.framework.logger.LogEnabled; 41 import org.apache.avalon.framework.logger.Logger; 42 import org.apache.avalon.framework.activity.Disposable; 43 import org.apache.excalibur.source.SourceResolver; 44 import org.apache.excalibur.source.Source; 45 import org.apache.cocoon.components.thread.RunnableManager; 46 import org.apache.xmlbeans.XmlOptions; 47 import org.outerx.daisy.x10Bookpubtype.PublicationTypeDocument; 48 49 import java.util.*; 50 import java.io.File ; 51 import java.security.SecureRandom ; 52 import java.text.DateFormat ; 53 54 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap; 55 56 57 public class BookPublisherImpl implements BookPublisher, Serviceable, Contextualizable, ThreadSafe, LogEnabled, Disposable { 58 private ServiceManager serviceManager; 59 private Context context; 60 private Logger logger; 61 private ConcurrentReaderHashMap activeTasks = new ConcurrentReaderHashMap(); 62 private RunnableManager runnableManager; 63 64 public void enableLogging(Logger logger) { 65 this.logger = logger; 66 } 67 68 public void service(ServiceManager serviceManager) throws ServiceException { 69 this.serviceManager = serviceManager; 70 this.runnableManager = (RunnableManager)serviceManager.lookup(RunnableManager.ROLE); 71 } 72 73 public void contextualize(Context context) throws ContextException { 74 this.context = context; 75 } 76 77 public void dispose() { 78 serviceManager.release(runnableManager); 79 } 80 81 public String [] publishBook(Repository repository, VariantKey bookDefinition, long dataBranchId, long dataLanguageId, 82 String dataVersion, Locale locale, String bookInstanceName, String bookInstanceLabel, 83 String daisyCocoonPath, String daisyContextPath, PublicationSpec[] specs, BookAcl acl) throws Exception { 84 for (int i = 0; i < specs.length; i++) { 86 String name = specs[i].getPublicationOutputName(); 87 for (int j = 0; j < specs.length; j++) { 88 if (i != j && specs[j].getPublicationOutputName().equals(name)) { 89 throw new RuntimeException ("Found duplicate publication name: \"" + name + "\"."); 90 } 91 } 92 } 93 94 AclResult result = BookAclEvaluator.evaluate(acl, repository.getUserId(), repository.getActiveRoleIds()); 96 if (!result.canManage()) 97 throw new RuntimeException ("The specified ACL excludes manage permission for the person starting the publication, which is disallowed."); 98 99 BookStore bookStore = (BookStore)repository.getExtension("BookStore"); 100 BookInstance bookInstance = bookStore.createBookInstance(bookInstanceName, bookInstanceLabel); 101 bookInstance.setAcl(acl); 102 103 repository = (Repository)((RemoteRepositoryImpl)repository).clone(); 105 106 BookPublishTask bookPublishTask = new BookPublishTask(bookDefinition, dataBranchId, dataLanguageId, dataVersion, 107 locale, specs, bookInstance, daisyContextPath, daisyCocoonPath, repository, serviceManager, context); 108 109 BackgroundTaskExecutor bte = new BackgroundTaskExecutor(bookPublishTask, this, logger, context, serviceManager); 110 synchronized(this) { 111 String taskId = generateTaskId(); 112 while (activeTasks.contains(taskId)) { 113 taskId = generateTaskId(); 114 } 115 116 activeTasks.put(taskId, bte); 117 try { 118 bte.setTaskId(taskId); 119 runnableManager.execute(bte); 120 } catch (Throwable e) { 121 activeTasks.remove(taskId); 122 throw new Exception ("Error starting background book publication task.", e); 123 } 124 return new String [] { taskId, bookInstance.getName() }; 125 } 126 } 127 128 public String [] getTaskState(String taskId) { 129 BackgroundTaskExecutor bte = (BackgroundTaskExecutor)activeTasks.get(taskId); 130 return bte != null ? bte.getBookPublishTask().getState() : null; 131 } 132 133 public PublishTaskInfo[] getTaskOverview(Locale locale) { 134 List result = new ArrayList(); 135 BackgroundTaskExecutor[] executors = (BackgroundTaskExecutor[])activeTasks.values().toArray(new BackgroundTaskExecutor[0]); 136 DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale); 137 for (int i = 0; i < executors.length; i++) { 138 PublishTaskInfo taskInfo = new PublishTaskInfo(executors[i].getTaskId(), 139 executors[i].getBookPublishTask().getBookInstance().getName(), 140 executors[i].getBookPublishTask().getRepository().getUserId(), 141 executors[i].getBookPublishTask().getRepository().getUserDisplayName(), 142 executors[i].getBookPublishTask().getState(), 143 dateTimeFormat.format(executors[i].getStarted())); 144 result.add(taskInfo); 145 } 146 return (PublishTaskInfo[])result.toArray(new PublishTaskInfo[result.size()]); 147 } 148 149 152 protected void taskEnded(String taskId) { 153 activeTasks.remove(taskId); 154 } 155 156 private static String generateTaskId() throws Exception { 157 byte[] bytes = new byte[15]; 158 SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); 159 random.nextBytes(bytes); 160 return toHexString(bytes); 161 } 162 163 private static String toHexString(byte[] b) { 164 StringBuffer sb = new StringBuffer (b.length * 2); 165 for (int i = 0; i < b.length; i++) { 166 sb.append(hexChar[(b[i] & 0xf0) >>> 4]); 167 sb.append(hexChar[b[i] & 0x0f]); 168 } 169 return sb.toString(); 170 } 171 172 private final static char[] hexChar = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 173 174 public PublicationTypeInfo[] getAvailablePublicationTypes(String daisyContextPath) throws Exception { 175 SourceResolver sourceResolver = null; 176 Source source = null; 177 try { 178 sourceResolver = (SourceResolver)serviceManager.lookup(SourceResolver.ROLE); 179 source = sourceResolver.resolveURI("wikidata:/books/publicationtypes"); 180 if (!(source instanceof WikiDataSource)) { throw new Exception ("Expected a WikiDataSource when resolving the publicationtypes directory."); 182 } 183 WikiDataSource wikiDataSource = (WikiDataSource) source; 184 Collection children = wikiDataSource.getChildren(); 185 List result = new ArrayList(); 186 XmlOptions xmlOptions = new XmlOptions().setLoadUseXMLReader(LocalSAXParserFactory.newXmlReader()); 187 Iterator childIterator = children.iterator(); 188 while (childIterator.hasNext()){ 189 WikiDataSource child = (WikiDataSource) childIterator.next(); 190 File publicationTypeXmlFile = new File (child.getFile(), "publicationtype.xml"); 191 if (child.isCollection() && publicationTypeXmlFile.exists()) { 192 String label = null; 193 try { 194 label = PublicationTypeDocument.Factory.parse(publicationTypeXmlFile, xmlOptions).getPublicationType().getLabel(); 195 } catch (Throwable e) { 196 logger.error("Error parsing publicationtype.xml at " + publicationTypeXmlFile.getAbsolutePath(), e); 197 } 198 if (label != null) 199 result.add(new PublicationTypeInfo(child.getName(), label)); 200 } 201 } 202 return (PublicationTypeInfo[])result.toArray(new PublicationTypeInfo[result.size()]); 203 } finally { 204 if (source != null) 205 sourceResolver.release(source); 206 if (sourceResolver != null) 207 serviceManager.release(sourceResolver); 208 } 209 } 210 211 public Map getDefaultProperties(String publicationTypeName, String daisyContextPath) throws Exception { 212 return PublicationTypeBuilder.loadProperties(publicationTypeName, daisyContextPath, serviceManager); 213 } 214 } 215 | Popular Tags |