1 19 20 package org.netbeans.modules.tomcat5.config; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.io.BufferedOutputStream ; 25 import java.io.ByteArrayInputStream ; 26 import java.io.File ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.io.OutputStream ; 30 import java.io.StringWriter ; 31 import java.util.ArrayList ; 32 import java.util.Collections ; 33 import java.util.HashMap ; 34 import java.util.HashSet ; 35 import java.util.List ; 36 import java.util.Set ; 37 import javax.enterprise.deploy.model.DDBean ; 38 import javax.enterprise.deploy.model.DDBeanRoot ; 39 import javax.enterprise.deploy.model.DeployableObject ; 40 import javax.enterprise.deploy.model.XpathEvent ; 41 import javax.enterprise.deploy.model.XpathListener ; 42 import javax.enterprise.deploy.spi.DConfigBeanRoot ; 43 import javax.enterprise.deploy.spi.DeploymentConfiguration ; 44 import javax.enterprise.deploy.spi.exceptions.BeanNotFoundException ; 45 import javax.enterprise.deploy.spi.exceptions.ConfigurationException ; 46 import javax.swing.text.BadLocationException ; 47 import javax.swing.text.StyledDocument ; 48 import org.netbeans.modules.j2ee.deployment.common.api.Datasource; 49 import org.netbeans.modules.j2ee.deployment.common.api.DatasourceAlreadyExistsException; 50 import org.netbeans.modules.schema2beans.BaseBean; 51 import org.netbeans.modules.schema2beans.Schema2BeansException; 52 import org.netbeans.modules.tomcat5.TomcatManager; 53 import org.netbeans.modules.tomcat5.TomcatManager.TomcatVersion; 54 import org.netbeans.modules.tomcat5.config.gen.Context; 55 import org.netbeans.modules.tomcat5.config.gen.Parameter; 56 import org.netbeans.modules.tomcat5.config.gen.ResourceParams; 57 import org.openide.DialogDisplayer; 58 import org.openide.ErrorManager; 59 import org.openide.NotifyDescriptor; 60 import org.openide.cookies.EditorCookie; 61 import org.openide.cookies.SaveCookie; 62 import org.openide.filesystems.FileLock; 63 import org.openide.filesystems.FileObject; 64 import org.openide.filesystems.FileSystem; 65 import org.openide.filesystems.FileUtil; 66 import org.openide.loaders.DataObject; 67 import org.openide.loaders.DataObjectNotFoundException; 68 import org.openide.text.NbDocument; 69 import org.openide.util.NbBundle; 70 71 76 public class WebappConfiguration implements DeploymentConfiguration , PropertyChangeListener , 77 XpathListener { 78 79 private final DeployableObject deplObj; 80 private final TomcatVersion tomcatVersion; 81 82 private DataObject contextDataObject; 83 private File contextXml; 84 private Context context; 85 86 private final String ATTR_PATH = "path"; 88 89 public WebappConfiguration (DeployableObject deplObj, TomcatVersion tomcatVersion) { 90 this.deplObj = deplObj; 91 this.tomcatVersion = tomcatVersion; 92 } 93 94 100 public void init(File contextXml) { 101 this.contextXml = contextXml; 102 getContext(); 103 if (contextDataObject == null) { 104 try { 105 contextDataObject = DataObject.find(FileUtil.toFileObject(contextXml)); 106 contextDataObject.addPropertyChangeListener(this); 107 } catch(DataObjectNotFoundException donfe) { 108 ErrorManager.getDefault().notify(donfe); 109 } 110 } 111 DDBeanRoot root = deplObj.getDDBeanRoot(); 113 if (root != null) { 114 root.addXpathListener("/web-app/resource-ref", this); } 118 } 119 120 126 public synchronized Context getContext() { 127 if (context == null) { 128 try { 129 if (contextXml.exists()) { 130 try { 132 context = Context.createGraph(contextXml); 133 } catch (IOException ioe) { 134 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe); 135 } catch (RuntimeException re) { 136 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, re); 138 } 139 } else { 140 context = genereateContext(); 142 writefile(contextXml); 143 } 144 } catch (ConfigurationException ce) { 145 ErrorManager.getDefault().notify(ce); 146 } 147 } 148 return context; 149 } 150 151 156 public String getContextPath() throws ConfigurationException { 157 Context ctx = getContext(); 158 if (ctx == null) { throw new ConfigurationException ("Context.xml is not parseable, cannot read the context path value."); } 161 return ctx.getAttributeValue(ATTR_PATH); 162 } 163 164 165 168 Set <Datasource> getDatasources() { 169 Context context = getContext(); 170 if (context == null) { ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "Context.xml is not parseable, cannot get the module datasources"); return Collections.<Datasource>emptySet(); 173 } 174 Set <Datasource> result = new HashSet <Datasource>(); 175 int length = context.getResource().length; 176 if (tomcatVersion != TomcatVersion.TOMCAT_50) { 177 for (int i = 0; i < length; i++) { 179 String type = context.getResourceType(i); 180 if ("javax.sql.DataSource".equals(type)) { String name = context.getResourceName(i); 182 String username = context.getResourceUsername(i); 183 String url = context.getResourceUrl(i); 184 String password = context.getResourcePassword(i); 185 String driverClassName = context.getResourceDriverClassName(i); 186 if (name != null && username != null && url != null && driverClassName != null) { 187 result.add(new TomcatDatasource(username, url, password, name, driverClassName)); 189 } 190 } 191 } 192 } else { 193 ResourceParams[] resourceParams = context.getResourceParams(); 195 for (int i = 0; i < length; i++) { 196 String type = context.getResourceType(i); 197 if ("javax.sql.DataSource".equals(type)) { String name = context.getResourceName(i); 199 for (int j = 0; j < resourceParams.length; j++) { 201 if (name.equals(resourceParams[j].getName())) { 202 Parameter[] params = resourceParams[j].getParameter(); 203 HashMap paramNameValueMap = new HashMap (params.length); 204 for (Parameter parameter : params) { 205 paramNameValueMap.put(parameter.getName(), parameter.getValue()); 206 } 207 String username = (String ) paramNameValueMap.get("username"); String url = (String ) paramNameValueMap.get("url"); String password = (String ) paramNameValueMap.get("password"); String driverClassName = (String ) paramNameValueMap.get("driverClassName"); if (username != null && url != null && driverClassName != null) { 212 result.add(new TomcatDatasource(username, url, password, name, driverClassName)); 214 } 215 } 216 } 217 } 218 } 219 } 220 return result; 221 } 222 223 224 Datasource createDatasource(String jndiName, String url, String username, String password, String driver) 225 throws ConfigurationException , DatasourceAlreadyExistsException { 226 return createJDBCReference(jndiName, url, username, password, driver); 227 } 228 229 232 public void setContextPath(String contextPath) throws ConfigurationException { 233 if (!isCorrectCP(contextPath)) { 236 String ctxRoot = contextPath; 237 java.util.StringTokenizer tok = new java.util.StringTokenizer (contextPath,"/"); StringBuffer buf = new StringBuffer (); while (tok.hasMoreTokens()) { 240 buf.append("/"+tok.nextToken()); } 242 ctxRoot = buf.toString(); 243 NotifyDescriptor desc = new NotifyDescriptor.Message( 244 NbBundle.getMessage (WebappConfiguration.class, "MSG_invalidCP", contextPath), 245 NotifyDescriptor.Message.INFORMATION_MESSAGE); 246 DialogDisplayer.getDefault().notify(desc); 247 contextPath = ctxRoot; 248 } 249 final String newContextPath = contextPath; 250 modifyContext(new ContextModifier() { 251 public void modify(Context context) { 252 if (tomcatVersion == TomcatVersion.TOMCAT_50) { 254 String oldContextPath = context.getAttributeValue(ATTR_PATH); 255 String oldPrefix = context.getLoggerPrefix(); 256 if (oldPrefix != null 257 && oldPrefix.equals(computeLoggerPrefix(oldContextPath))) { 258 context.setLoggerPrefix(computeLoggerPrefix(newContextPath)); 259 } 260 } 261 context.setAttributeValue(ATTR_PATH, newContextPath); 262 } 263 }); 264 } 265 266 267 public DataObject getContextDataObject() { 268 return contextDataObject; 269 } 270 271 273 276 public void propertyChange(PropertyChangeEvent evt) { 277 if (evt.getPropertyName() == DataObject.PROP_MODIFIED && 278 evt.getNewValue() == Boolean.FALSE) { 279 context = null; 281 } 282 } 283 284 286 public void fireXpathEvent(XpathEvent xpe) { 287 DDBean eventDDBean = xpe.getBean(); 288 if ("/web-app/resource-ref".equals(eventDDBean.getXpath())) { if (xpe.isAddEvent()) { 291 String [] name = eventDDBean.getText("res-ref-name"); String [] type = eventDDBean.getText("res-type"); if (name.length > 0 && type.length > 0) { 294 try { 295 addResReference(name[0], type[0]); 296 } catch (ConfigurationException ce) { 297 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ce); 298 } 299 } 300 } 301 } 302 } 303 304 306 public DeployableObject getDeployableObject () { 307 return deplObj; 308 } 309 310 public void save (OutputStream os) throws ConfigurationException { 311 Context ctx = getContext(); 312 if (ctx == null) { 313 throw new ConfigurationException ("Cannot read configuration, it is probably in an inconsistent state."); } 315 try { 316 ctx.write(os); 317 } catch (IOException ioe) { 318 throw new ConfigurationException (ioe.getLocalizedMessage()); 319 } 320 } 321 322 324 public DConfigBeanRoot getDConfigBeanRoot (DDBeanRoot dDBeanRoot) 325 throws ConfigurationException { 326 return null; 327 } 328 329 public void removeDConfigBean (DConfigBeanRoot dConfigBeanRoot) 330 throws BeanNotFoundException { 331 throw new BeanNotFoundException ("Bean not found in WebappConfiguration " + dConfigBeanRoot); } 333 334 public void restore (InputStream is) 335 throws ConfigurationException { 336 } 337 338 public DConfigBeanRoot restoreDConfigBean (InputStream is, DDBeanRoot dDBeanRoot) 339 throws ConfigurationException { 340 return null; 341 } 342 343 public void saveDConfigBean (OutputStream os, DConfigBeanRoot dConfigBeanRoot) 344 throws ConfigurationException { 345 } 346 347 348 350 353 private Context genereateContext() { 354 Context newContext = new Context(); 355 String path = ""; newContext.setAttributeValue(ATTR_PATH, path); 357 358 if (tomcatVersion == TomcatVersion.TOMCAT_50) { 360 newContext.setLogger(true); 362 newContext.setLoggerClassName("org.apache.catalina.logger.FileLogger"); newContext.setLoggerPrefix(computeLoggerPrefix(path)); 364 newContext.setLoggerSuffix(".log"); newContext.setLoggerTimestamp("true"); } 367 return newContext; 368 } 369 370 private Datasource createJDBCReference(final String name, final String url, final String username, final String password, final String driverClassName) 371 throws ConfigurationException , DatasourceAlreadyExistsException { 372 List <Datasource> conflictingDS = new ArrayList <Datasource>(); 374 for (Datasource datasource : getDatasources()) { 375 if (name.equals(datasource.getJndiName())) { 376 conflictingDS.add(datasource); 377 } 378 } 379 if (conflictingDS.size() > 0) { 380 throw new DatasourceAlreadyExistsException(conflictingDS); 381 } 382 if (tomcatVersion != TomcatVersion.TOMCAT_50) { 383 modifyContext(new ContextModifier() { 385 public void modify(Context context) { 386 int idx = context.addResource(true); 387 context.setResourceName(idx, name); 388 context.setResourceAuth(idx, "Container"); context.setResourceType(idx, "javax.sql.DataSource"); context.setResourceDriverClassName(idx, driverClassName); 391 context.setResourceUrl(idx, url); 392 context.setResourceUsername(idx, username); 393 context.setResourcePassword(idx, password); 394 context.setResourceMaxActive(idx, "20"); context.setResourceMaxIdle(idx, "10"); context.setResourceMaxWait(idx, "-1"); } 398 }); 399 } else { 400 modifyContext(new ContextModifier() { 402 public void modify(Context context) { 403 int idx = context.addResource(true); 404 context.setResourceName(idx, name); 405 context.setResourceAuth(idx, "Container"); context.setResourceType(idx, "javax.sql.DataSource"); 408 ResourceParams[] resourceParams = context.getResourceParams(); 410 for (int i = 0; i < resourceParams.length; i++) { 411 if (name.equals(resourceParams[i].getName())) { 412 context.removeResourceParams(resourceParams[i]); 415 } 416 } 417 ResourceParams newResourceParams = createResourceParams( 418 name, 419 new Parameter[] { 420 createParameter("factory", "org.apache.commons.dbcp.BasicDataSourceFactory"), createParameter("driverClassName", driverClassName), createParameter("url", url), createParameter("username", username), createParameter("password", password), createParameter("maxActive", "20"), createParameter("maxIdle", "10"), createParameter("maxWait", "-1") } 429 ); 430 context.addResourceParams(newResourceParams); 431 } 432 }); 433 } 434 return new TomcatDatasource(username, url, password, name, driverClassName); 435 } 436 437 442 private void addResReference(final String name, final String type) throws ConfigurationException { 443 if ("javax.sql.DataSource".equals(type)) { modifyContext(new ContextModifier() { 445 public void modify(Context context) { 446 int lengthResource = context.getResource().length; 448 for (int i = 0; i < lengthResource; i++) { 449 if (name.equals(context.getResourceName(i))) { 450 return; 452 } 453 } 454 int lengthResourceLink = context.getResourceLink().length; 456 for (int i = 0; i < lengthResourceLink; i++) { 457 if (name.equals(context.getResourceLinkName(i))) { 458 return; 460 } 461 } 462 int idx = context.addResourceLink(true); 465 context.setResourceLinkName(idx, name); 466 context.setResourceLinkGlobal(idx, name); 467 context.setResourceLinkType(idx, "javax.sql.DataSource"); } 469 }); 470 } 471 } 472 473 479 private void modifyContext(ContextModifier modifier) throws ConfigurationException { 480 assert contextDataObject != null : "DataObject has not been initialized yet"; try { 482 EditorCookie editor = (EditorCookie)contextDataObject.getCookie(EditorCookie.class); 484 StyledDocument doc = editor.getDocument(); 485 if (doc == null) { 486 doc = editor.openDocument(); 487 } 488 489 Context newContext = null; 491 try { 492 byte[] docString = doc.getText(0, doc.getLength()).getBytes(); 494 newContext = Context.createGraph(new ByteArrayInputStream (docString)); 495 } catch (RuntimeException e) { 496 Context oldContext = getContext(); 497 if (oldContext == null) { 498 throw new ConfigurationException ("Configuration data are not parseable cannot perform changes."); } 502 NotifyDescriptor notDesc = new NotifyDescriptor.Confirmation( 504 NbBundle.getMessage(WebappConfiguration.class, "MSG_ContextXmlNotValid"), 505 NotifyDescriptor.OK_CANCEL_OPTION); 506 Object result = DialogDisplayer.getDefault().notify(notDesc); 507 if (result == NotifyDescriptor.CANCEL_OPTION) { 508 return; 510 } 511 newContext = oldContext; 513 } 514 515 modifier.modify(newContext); 517 518 boolean modified = contextDataObject.isModified(); 520 replaceDocument(doc, newContext); 521 if (!modified) { 522 SaveCookie cookie = (SaveCookie)contextDataObject.getCookie(SaveCookie.class); 523 if (cookie != null) { 524 cookie.save(); 525 } 526 } 527 context = newContext; 528 } catch (BadLocationException ble) { 529 throw (ConfigurationException )(new ConfigurationException ().initCause(ble)); 530 } catch (IOException ioe) { 531 throw (ConfigurationException )(new ConfigurationException ().initCause(ioe)); 532 } 533 } 534 535 private Parameter createParameter(String name, String value) { 536 Parameter parameter = new Parameter(); 537 parameter.setName(name); 538 parameter.setValue(value); 539 return parameter; 540 } 541 542 private ResourceParams createResourceParams(String name, Parameter[] parameters) { 543 ResourceParams resourceParams = new ResourceParams(); 544 resourceParams.setName(name); 545 for (int i = 0; i < parameters.length; i++) { 546 resourceParams.addParameter(parameters[i]); 547 } 548 return resourceParams; 549 } 550 551 555 private String computeLoggerPrefix(String contextPath) { 556 return contextPath.length() > 0 557 ? contextPath.substring(1).replace('/', '_').concat(".") : "ROOT."; } 560 561 private void writefile(final File file) throws ConfigurationException { 562 try { 563 FileObject cfolder = FileUtil.toFileObject(file.getParentFile()); 564 if (cfolder == null) { 565 File parentFile = file.getParentFile(); 566 try { 567 cfolder = FileUtil.toFileObject(parentFile.getParentFile()).createFolder(parentFile.getName()); 568 } catch (IOException ioe) { 569 throw new ConfigurationException (NbBundle.getMessage(WebappConfiguration.class, "MSG_FailedToCreateConfigFolder", parentFile.getAbsolutePath())); 570 } 571 } 572 final FileObject folder = cfolder; 573 FileSystem fs = folder.getFileSystem(); 574 fs.runAtomicAction(new FileSystem.AtomicAction() { 575 public void run() throws IOException { 576 OutputStream os = null; 577 FileLock lock = null; 578 try { 579 String name = file.getName(); 580 FileObject configFO = folder.getFileObject(name); 581 if (configFO == null) { 582 configFO = folder.createData(name); 583 } 584 lock = configFO.lock(); 585 os = new BufferedOutputStream (configFO.getOutputStream(lock), 4086); 586 Context ctx = getContext(); 587 if (ctx != null) { 589 ctx.write(os); 590 } 591 } finally { 592 if (os != null) { 593 try { os.close(); } catch(IOException ioe) {} 594 } 595 if (lock != null) 596 lock.releaseLock(); 597 } 598 } 599 }); 600 } catch (IOException e) { 601 throw new ConfigurationException (e.getLocalizedMessage ()); 602 } 603 } 604 605 608 private void replaceDocument(final StyledDocument doc, BaseBean graph) { 609 final StringWriter out = new StringWriter (); 610 try { 611 graph.write(out); 612 } catch (Schema2BeansException ex) { 613 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 614 } catch (IOException ioe) { 615 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe); 616 } 617 NbDocument.runAtomic(doc, new Runnable () { 618 public void run() { 619 try { 620 doc.remove(0, doc.getLength()); 621 doc.insertString(0, out.toString(), null); 622 } catch (BadLocationException ble) { 623 ErrorManager.getDefault().notify(ble); 624 } 625 } 626 }); 627 } 628 629 private boolean isCorrectCP(String contextPath) { 632 boolean correct=true; 633 if (!contextPath.equals("") && !contextPath.startsWith("/")) correct=false; else if (contextPath.endsWith("/")) correct=false; else if (contextPath.indexOf("//")>=0) correct=false; return correct; 637 } 638 639 641 private interface ContextModifier { 642 void modify(Context context); 643 } 644 } 645 | Popular Tags |