View Javadoc
1   /*
2    * Copyright 2001-2008 The Apache Software Foundation.
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   */
17  package org.apache.juddi.config;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.StringReader;
23  import java.net.URI;
24  import java.net.URISyntaxException;
25  import java.net.URL;
26  import java.text.SimpleDateFormat;
27  import java.util.ArrayList;
28  import java.util.Date;
29  import java.util.Enumeration;
30  import java.util.List;
31  import java.util.StringTokenizer;
32  import java.util.UUID;
33  import java.util.jar.JarEntry;
34  import java.util.jar.JarFile;
35  import java.util.logging.Level;
36  import java.util.logging.Logger;
37  
38  import javax.persistence.EntityManager;
39  import javax.persistence.EntityTransaction;
40  import javax.xml.bind.JAXB;
41  import javax.xml.bind.JAXBContext;
42  import javax.xml.bind.JAXBElement;
43  import javax.xml.bind.JAXBException;
44  import javax.xml.bind.Unmarshaller;
45  import javax.xml.stream.XMLInputFactory;
46  import javax.xml.stream.XMLStreamException;
47  import javax.xml.stream.XMLStreamReader;
48  import javax.xml.transform.stream.StreamSource;
49  
50  import org.apache.commons.configuration.Configuration;
51  import org.apache.commons.configuration.ConfigurationException;
52  import org.apache.commons.logging.Log;
53  import org.apache.commons.logging.LogFactory;
54  import org.apache.juddi.ClassUtil;
55  import org.apache.juddi.api.impl.AuthenticatedService;
56  import org.apache.juddi.api.impl.UDDIInquiryImpl;
57  import org.apache.juddi.api.impl.UDDIPublicationImpl;
58  import org.apache.juddi.keygen.KeyGenerator;
59  import org.apache.juddi.mapping.MappingApiToModel;
60  import org.apache.juddi.mapping.MappingModelToApi;
61  import org.apache.juddi.model.ReplicationConfiguration;
62  import org.apache.juddi.model.UddiEntityPublisher;
63  import org.apache.juddi.replication.ReplicationNotifier;
64  import org.apache.juddi.v3.client.cryptor.XmlUtils;
65  import org.apache.juddi.v3.error.ErrorMessage;
66  import org.apache.juddi.v3.error.FatalErrorException;
67  import org.apache.juddi.v3.error.InvalidKeyPassedException;
68  import org.apache.juddi.v3.error.KeyUnavailableException;
69  import org.apache.juddi.v3.error.ValueNotAllowedException;
70  import org.apache.juddi.validation.ValidatePublish;
71  import org.apache.juddi.validation.ValidateReplication;
72  import org.apache.juddi.validation.ValidateUDDIKey;
73  import org.uddi.api_v3.SaveBusiness;
74  import org.uddi.api_v3.SaveTModel;
75  import org.uddi.api_v3.TModel;
76  import org.uddi.repl_v3.Operator;
77  import org.uddi.v3_service.DispositionReportFaultMessage;
78  
79  /**
80   * This class is called when jUDDI starts up
81   *
82   * @author <a href="mailto:jfaath@apache.org">Jeff Faath</a>
83   * @author <a href="mailto:alexoree@apache.org">Alex O'Ree</a>
84   * @see org.apache.juddi.servlets.RegistryServlet
85   */
86  public class Install {
87  
88          public static final String FILE_BUSINESSENTITY = "_BusinessEntity.xml";
89          public static final String FILE_PUBLISHER = "_Publisher.xml";
90          public static final String FILE_TMODELKEYGEN = "_tModelKeyGen.xml";
91          public static final String FILE_TMODELS = "_tModels.xml";
92  
93          public static final String FILE_PERSISTENCE = "persistence.xml";
94          public static final String JUDDI_INSTALL_DATA_DIR = "juddi_install_data/";
95          public static final String JUDDI_CUSTOM_INSTALL_DATA_DIR = "juddi_custom_install_data/";
96          public static final String FILE_REPLICATION_CONFIG = "_replicationConfiguration.xml";
97          public static final Log log = LogFactory.getLog(Install.class);
98  
99          protected static void install(Configuration config) throws JAXBException, DispositionReportFaultMessage, IOException, ConfigurationException, XMLStreamException {
100 
101                 EntityManager em = PersistenceManager.getEntityManager();
102                 EntityTransaction tx = em.getTransaction();
103 
104                 UddiEntityPublisher rootPublisher = null;
105 
106                 try {
107                         tx.begin();
108                         boolean seedAlways = config.getBoolean("juddi.seed.always", false);
109                         boolean alreadyInstalled = alreadyInstalled(config);
110                         if (!seedAlways && alreadyInstalled) {
111                                 throw new FatalErrorException(new ErrorMessage("errors.install.AlreadyInstalled"));
112                         }
113 
114                         String rootPublisherStr = config.getString(Property.JUDDI_ROOT_PUBLISHER);
115                         String fileRootTModelKeygen = rootPublisherStr + FILE_TMODELKEYGEN;
116                         TModel rootTModelKeyGen = (TModel) buildInstallEntity(fileRootTModelKeygen, "org.uddi.api_v3", config);
117                         String fileRootBusinessEntity = rootPublisherStr + FILE_BUSINESSENTITY;
118                         org.uddi.api_v3.BusinessEntity rootBusinessEntity = (org.uddi.api_v3.BusinessEntity) buildInstallEntity(fileRootBusinessEntity, "org.uddi.api_v3", config);
119 
120                         String rootPartition = getRootPartition(rootTModelKeyGen);
121                         //JUDDI-645
122                         String nodeId = config.getString(Property.JUDDI_NODE_ID, getNodeId(rootBusinessEntity.getBusinessKey(), rootPartition));
123                         //getNodeId(rootBusinessEntity.getBusinessKey(), rootPartition);
124                         String rootbizkey = getNodeId(rootBusinessEntity.getBusinessKey(), rootPartition);
125                         String fileRootPublisher = rootPublisherStr + FILE_PUBLISHER;
126                         String fileReplicationConfig = rootPublisherStr + FILE_REPLICATION_CONFIG;
127                         org.uddi.repl_v3.ReplicationConfiguration replicationCfg = (org.uddi.repl_v3.ReplicationConfiguration) buildInstallEntityAlt(fileReplicationConfig, org.uddi.repl_v3.ReplicationConfiguration.class, config);
128                         if (!alreadyInstalled) {
129                                 log.info("Loading the root Publisher from file " + fileRootPublisher);
130 
131                                 rootPublisher = installPublisher(em, fileRootPublisher, config);
132                                 installRootPublisherKeyGen(em, rootTModelKeyGen, rootPartition, rootPublisher, nodeId);
133                                 rootBusinessEntity.setBusinessKey(rootbizkey);
134                                 installBusinessEntity(true, em, rootBusinessEntity, rootPublisher, rootPartition, config, nodeId);
135                                 installReplicationConfiguration(em, replicationCfg, config, nodeId);
136                         } else {
137                                 log.debug("juddi.seed.always reapplies all seed files except for the root data.");
138                         }
139 
140                         List<String> juddiPublishers = getPublishers(config);
141                         for (String publisherStr : juddiPublishers) {
142                                 String filePublisher = publisherStr + FILE_PUBLISHER;
143                                 String fileTModelKeygen = publisherStr + FILE_TMODELKEYGEN;
144                                 TModel tModelKeyGen = (TModel) buildInstallEntity(fileTModelKeygen, "org.uddi.api_v3", config);
145                                 String fileBusinessEntity = publisherStr + FILE_BUSINESSENTITY;
146                                 org.uddi.api_v3.BusinessEntity businessEntity = (org.uddi.api_v3.BusinessEntity) buildInstallEntity(fileBusinessEntity, "org.uddi.api_v3", config);
147                                 UddiEntityPublisher publisher = installPublisher(em, filePublisher, config);
148                                 if (publisher == null) {
149                                         throw new ConfigurationException("File " + filePublisher + " not found.");
150                                 } else {
151                                         if (tModelKeyGen != null) {
152                                                 installPublisherKeyGen(em, tModelKeyGen, publisher, nodeId);
153                                         }
154                                         if (businessEntity != null) {
155                                                 installBusinessEntity(false, em, businessEntity, publisher, null, config, nodeId);
156                                         }
157                                         String fileTModels = publisherStr + FILE_TMODELS;
158                                         installSaveTModel(em, fileTModels, publisher, nodeId, config);
159                                 }
160                         }
161 
162                         tx.commit();
163                 } catch (DispositionReportFaultMessage dr) {
164                         log.error(dr.getMessage(), dr);
165                         tx.rollback();
166                         throw dr;
167                 } catch (JAXBException je) {
168                         log.error(je.getMessage(), je);
169                         tx.rollback();
170                         throw je;
171                 } catch (IOException ie) {
172                         log.error(ie.getMessage(), ie);
173                         tx.rollback();
174                         throw ie;
175                 } catch (XMLStreamException ex) {
176                         log.error(ex.getMessage(), ex);
177                         tx.rollback();
178                         throw ex;
179             } finally {
180                         if (tx.isActive()) {
181                                 tx.rollback();
182                         }
183                         em.close();
184                 }
185         }
186 
187         protected static void uninstall() {
188                 // Close the open emf, open a new one with Persistence.create...(String, Map) and overwrite the property that handles the table 
189                 // generation. The persistence.xml file will have to be read in to determine which property
190                 // to overwrite.  The property will be specific to the provider.  
191                 // Hibernate:  <property name="hibernate.hbm2ddl.auto" value="update"/> ->use "create-drop" or just "drop"?
192                 // OpenJPA: openjpa.jdbc.SynchronizeMappings=buildSchema(SchemaAction='add,deleteTableContents')
193                 // etc...(find more)
194                 // Then close this emf.  Question:  is the original emf reusable or will closing it cause problems?
195 
196         }
197 
198         /**
199          * Checks if there is a database with a root publisher. If it is not
200          * found an
201          *
202          * @param config
203          * @return true if it finds a database with the root publisher in it.
204          * @throws ConfigurationException
205          */
206         protected static boolean alreadyInstalled(Configuration config) throws ConfigurationException {
207 
208                 String rootPublisherStr = config.getString(Property.JUDDI_ROOT_PUBLISHER);
209                 log.info("Checking if jUDDI is seeded by searching for root publisher " + rootPublisherStr);
210                 org.apache.juddi.model.Publisher publisher = null;
211                 int numberOfTries = 0;
212                 while (numberOfTries++ < 100) {
213                         EntityManager em = PersistenceManager.getEntityManager();
214                         EntityTransaction tx = em.getTransaction();
215                         try {
216                                 tx.begin();
217                                 publisher = em.find(org.apache.juddi.model.Publisher.class, rootPublisherStr);
218                                 tx.commit();
219                         } finally {
220                                 if (tx.isActive()) {
221                                         tx.rollback();
222                                 }
223                                 em.close();
224                         }
225                         if (publisher != null) {
226                                 return true;
227                         }
228 
229                         if (config.getBoolean(Property.JUDDI_LOAD_INSTALL_DATA, Property.DEFAULT_LOAD_INSTALL_DATA)) {
230                                 log.debug("Install data not yet installed.");
231                                 return false;
232                         } else {
233                                 try {
234                                         log.info("Install data not yet installed.");
235                                         log.info("Going to sleep and retry...");
236                                         Thread.sleep(1000l);
237                                 } catch (InterruptedException e) {
238                                         log.error(e.getMessage(), e);
239                                 }
240                         }
241                 }
242                 throw new ConfigurationException("Could not load the Root node data. Please check for errors.");
243         }
244 
245         protected static String getRootPartition(TModel rootTModelKeyGen) throws JAXBException, IOException, DispositionReportFaultMessage {
246                 String result = rootTModelKeyGen.getTModelKey().substring(0, rootTModelKeyGen.getTModelKey().lastIndexOf(KeyGenerator.PARTITION_SEPARATOR));
247 
248                 if (result == null || result.length() == 0) {
249                         throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.MalformedKey", result));
250                 }
251 
252                 // Must validate the root partition.  The first component should be a domain key and the any following
253                 // tokens should be a valid KSS.
254                 result = result.trim();
255                 if (result.endsWith(KeyGenerator.PARTITION_SEPARATOR) || result.startsWith(KeyGenerator.PARTITION_SEPARATOR)) {
256                         throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.MalformedKey", result));
257                 }
258 
259                 StringTokenizer tokenizer = new StringTokenizer(result.toLowerCase(), KeyGenerator.PARTITION_SEPARATOR);
260                 for (int count = 0; tokenizer.hasMoreTokens(); count++) {
261                         String nextToken = tokenizer.nextToken();
262 
263                         if (count == 0) {
264                                 if (!ValidateUDDIKey.isValidDomainKey(nextToken)) {
265                                         throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.MalformedKey", result));
266                                 }
267                         } else {
268                                 if (!ValidateUDDIKey.isValidKSS(nextToken)) {
269                                         throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.MalformedKey", result));
270                                 }
271                         }
272                 }
273 
274                 return result;
275         }
276 
277         protected static String getNodeId(String userNodeId, String rootPartition) throws DispositionReportFaultMessage {
278 
279                 String result = userNodeId;
280                 if (result == null || result.length() == 0) {
281                         result = rootPartition + KeyGenerator.PARTITION_SEPARATOR + UUID.randomUUID();
282                 } else {
283                         ValidateUDDIKey.validateUDDIv3Key(result);
284                         String keyPartition = result.substring(0, result.lastIndexOf(KeyGenerator.PARTITION_SEPARATOR));
285                         if (!rootPartition.equalsIgnoreCase(keyPartition)) {
286                                 throw new KeyUnavailableException(new ErrorMessage("errors.keyunavailable.BadPartition", userNodeId));
287                         }
288                 }
289                 return result;
290         }
291 
292         private static String installBusinessEntity(boolean isRoot, EntityManager em, org.uddi.api_v3.BusinessEntity rootBusinessEntity,
293                 UddiEntityPublisher rootPublisher, String rootPartition, Configuration config, String nodeId)
294                 throws JAXBException, DispositionReportFaultMessage, IOException {
295 
296                 if (isRoot) {
297                         validateRootBusinessEntity(rootBusinessEntity, rootPublisher, rootPartition, config);
298                 }
299 
300                 org.apache.juddi.model.BusinessEntity modelBusinessEntity = new org.apache.juddi.model.BusinessEntity();
301                 MappingApiToModel.mapBusinessEntity(rootBusinessEntity, modelBusinessEntity);
302 
303                 modelBusinessEntity.setAuthorizedName(rootPublisher.getAuthorizedName());
304                 modelBusinessEntity.setNodeId(nodeId);
305                 Date now = new Date();
306                 modelBusinessEntity.setCreated(now);
307                 modelBusinessEntity.setModified(now);
308                 modelBusinessEntity.setModifiedIncludingChildren(now);
309                 //JUDDI-645
310                 //modelBusinessEntity.setNodeId(modelBusinessEntity.getEntityKey());
311                 modelBusinessEntity.setNodeId(config.getString(Property.JUDDI_NODE_ID, modelBusinessEntity.getEntityKey()));
312 
313                 for (org.apache.juddi.model.BusinessService service : modelBusinessEntity.getBusinessServices()) {
314                         service.setAuthorizedName(rootPublisher.getAuthorizedName());
315                         service.setNodeId(modelBusinessEntity.getNodeId());
316                         service.setCreated(now);
317                         service.setModified(now);
318                         service.setModifiedIncludingChildren(now);
319                         //JUDDI-645
320                         //service.setNodeId(config.getString(Property.JUDDI_NODE_ID,modelBusinessEntity.getEntityKey()));
321                         //service.setNodeId(modelBusinessEntity.getEntityKey());
322 
323                         for (org.apache.juddi.model.BindingTemplate binding : service.getBindingTemplates()) {
324                                 binding.setAuthorizedName(rootPublisher.getAuthorizedName());
325                                 binding.setNodeId(nodeId);
326                                 binding.setCreated(now);
327                                 binding.setModified(now);
328                                 binding.setModifiedIncludingChildren(now);
329                                 //binding.setNodeId(modelBusinessEntity.getEntityKey());
330                                 //binding.setNodeId(config.getString(Property.JUDDI_NODE_ID,modelBusinessEntity.getEntityKey()));
331                                 //JUDDI-645
332 
333                         }
334                 }
335 
336                 em.persist(modelBusinessEntity);
337                 SaveBusiness sb = new SaveBusiness();
338                 sb.getBusinessEntity().add(rootBusinessEntity);
339                 ReplicationNotifier.enqueue(UDDIPublicationImpl.getChangeRecord(modelBusinessEntity, rootBusinessEntity, modelBusinessEntity.getNodeId()));
340 
341                 return modelBusinessEntity.getEntityKey();
342 
343         }
344 
345         // A watered down version of ValidatePublish's validateBusinessEntity, designed for the specific condition that this is run upon the initial
346         // jUDDI install.
347         private static void validateRootBusinessEntity(org.uddi.api_v3.BusinessEntity businessEntity, UddiEntityPublisher rootPublisher,
348                 String rootPartition, Configuration config)
349                 throws DispositionReportFaultMessage {
350 
351                 // A supplied businessService can't be null
352                 if (businessEntity == null) {
353                         throw new ValueNotAllowedException(new ErrorMessage("errors.businessentity.NullInput"));
354                 }
355 
356                 // The business key should already be set to the previously calculated and validated nodeId.  This validation is unnecessary but kept for 
357                 // symmetry with the other entity validations.
358                 String entityKey = businessEntity.getBusinessKey();
359                 if (entityKey == null || entityKey.length() == 0) {
360                         entityKey = rootPartition + KeyGenerator.PARTITION_SEPARATOR + UUID.randomUUID();
361                         businessEntity.setBusinessKey(entityKey);
362                 } else {
363                         // Per section 4.4: keys must be case-folded
364                         entityKey = entityKey.toLowerCase();
365                         businessEntity.setBusinessKey(entityKey);
366 
367                         ValidateUDDIKey.validateUDDIv3Key(entityKey);
368                         String keyPartition = entityKey.substring(0, entityKey.lastIndexOf(KeyGenerator.PARTITION_SEPARATOR));
369                         if (!rootPartition.equalsIgnoreCase(keyPartition)) {
370                                 throw new KeyUnavailableException(new ErrorMessage("errors.keyunavailable.BadPartition", entityKey));
371                         }
372                 }
373 
374                 ValidatePublish validatePublish = new ValidatePublish(rootPublisher, config.getString(Property.JUDDI_NODE_ID));
375 
376                 validatePublish.validateNames(businessEntity.getName());
377                 validatePublish.validateDiscoveryUrls(businessEntity.getDiscoveryURLs());
378                 validatePublish.validateContacts(businessEntity.getContacts(), config);
379                 validatePublish.validateCategoryBag(businessEntity.getCategoryBag(), config, true);
380                 validatePublish.validateIdentifierBag(businessEntity.getIdentifierBag(), config, true);
381 
382                 org.uddi.api_v3.BusinessServices businessServices = businessEntity.getBusinessServices();
383                 if (businessServices != null) {
384                         List<org.uddi.api_v3.BusinessService> businessServiceList = businessServices.getBusinessService();
385                         if (businessServiceList == null || businessServiceList.size() == 0) {
386                                 throw new ValueNotAllowedException(new ErrorMessage("errors.businessservices.NoInput"));
387                         }
388 
389                         for (org.uddi.api_v3.BusinessService businessService : businessServiceList) {
390                                 validateRootBusinessService(businessService, businessEntity, rootPublisher, rootPartition, config);
391                         }
392                 }
393 
394         }
395 
396         // A watered down version of ValidatePublish's validateBusinessService, designed for the specific condition that this is run upon the initial
397         // jUDDI install.
398         private static void validateRootBusinessService(org.uddi.api_v3.BusinessService businessService, org.uddi.api_v3.BusinessEntity parent,
399                 UddiEntityPublisher rootPublisher, String rootPartition, Configuration config)
400                 throws DispositionReportFaultMessage {
401 
402                 // A supplied businessService can't be null
403                 if (businessService == null) {
404                         throw new ValueNotAllowedException(new ErrorMessage("errors.businessservice.NullInput"));
405                 }
406 
407                 // A business key doesn't have to be provided, but if it is, it should match the parent business's key
408                 String parentKey = businessService.getBusinessKey();
409                 if (parentKey != null && parentKey.length() > 0) {
410                         if (!parentKey.equalsIgnoreCase(parent.getBusinessKey())) {
411                                 throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.ParentBusinessNotFound", parentKey + " " + businessService.getBusinessKey() + " " + businessService.getBusinessKey().length() + " " + parentKey.length()));
412                         }
413                 }
414 
415                 // Retrieve the service's passed key
416                 String entityKey = businessService.getServiceKey();
417                 if (entityKey == null || entityKey.length() == 0) {
418                         entityKey = rootPartition + KeyGenerator.PARTITION_SEPARATOR + UUID.randomUUID();
419                         businessService.setServiceKey(entityKey);
420                 } else {
421                         // Per section 4.4: keys must be case-folded
422                         entityKey = entityKey.toLowerCase();
423                         businessService.setServiceKey(entityKey);
424 
425                         ValidateUDDIKey.validateUDDIv3Key(entityKey);
426                         String keyPartition = entityKey.substring(0, entityKey.lastIndexOf(KeyGenerator.PARTITION_SEPARATOR));
427                         if (!rootPartition.equalsIgnoreCase(keyPartition)) {
428                                 throw new KeyUnavailableException(new ErrorMessage("errors.keyunavailable.BadPartition", entityKey));
429                         }
430                 }
431 
432                 ValidatePublish validatePublish = new ValidatePublish(rootPublisher, config.getString(Property.JUDDI_NODE_ID));
433 
434                 validatePublish.validateNames(businessService.getName());
435                 validatePublish.validateCategoryBag(businessService.getCategoryBag(), config, true);
436 
437                 org.uddi.api_v3.BindingTemplates bindingTemplates = businessService.getBindingTemplates();
438                 if (bindingTemplates != null) {
439                         List<org.uddi.api_v3.BindingTemplate> bindingTemplateList = bindingTemplates.getBindingTemplate();
440                         if (bindingTemplateList == null || bindingTemplateList.size() == 0) {
441                                 throw new ValueNotAllowedException(new ErrorMessage("errors.bindingtemplates.NoInput"));
442                         }
443 
444                         for (org.uddi.api_v3.BindingTemplate bindingTemplate : bindingTemplateList) {
445                                 validateRootBindingTemplate(bindingTemplate, businessService, rootPublisher, rootPartition, config);
446                         }
447                 }
448         }
449 
450         // A watered down version of ValidatePublish's validatBindingTemplate, designed for the specific condition that this is run upon the initial
451         // jUDDI install.
452         private static void validateRootBindingTemplate(org.uddi.api_v3.BindingTemplate bindingTemplate, org.uddi.api_v3.BusinessService parent,
453                 UddiEntityPublisher rootPublisher, String rootPartition, Configuration config)
454                 throws DispositionReportFaultMessage {
455 
456                 // A supplied businessService can't be null
457                 if (bindingTemplate == null) {
458                         throw new ValueNotAllowedException(new ErrorMessage("errors.bindingtemplate.NullInput"));
459                 }
460 
461                 // A service key doesn't have to be provided, but if it is, it should match the parent service's key
462                 String parentKey = bindingTemplate.getServiceKey();
463                 if (parentKey != null && parentKey.length() > 0) {
464                         if (!parentKey.equalsIgnoreCase(parent.getServiceKey())) {
465                                 throw new InvalidKeyPassedException(new ErrorMessage("errors.invalidkey.ParentServiceNotFound", parentKey));
466                         }
467                 }
468 
469                 // Retrieve the service's passed key
470                 String entityKey = bindingTemplate.getBindingKey();
471                 if (entityKey == null || entityKey.length() == 0) {
472                         entityKey = rootPartition + KeyGenerator.PARTITION_SEPARATOR + UUID.randomUUID();
473                         bindingTemplate.setBindingKey(entityKey);
474                 } else {
475                         // Per section 4.4: keys must be case-folded
476                         entityKey = entityKey.toLowerCase();
477                         bindingTemplate.setBindingKey(entityKey);
478 
479                         ValidateUDDIKey.validateUDDIv3Key(entityKey);
480                         String keyPartition = entityKey.substring(0, entityKey.lastIndexOf(KeyGenerator.PARTITION_SEPARATOR));
481                         if (!rootPartition.equalsIgnoreCase(keyPartition)) {
482                                 throw new KeyUnavailableException(new ErrorMessage("errors.keyunavailable.BadPartition", entityKey));
483                         }
484                 }
485 
486                 ValidatePublish validatePublish = new ValidatePublish(rootPublisher, config.getString(Property.JUDDI_NODE_ID));
487 
488                 validatePublish.validateCategoryBag(bindingTemplate.getCategoryBag(), config, true);
489                 validatePublish.validateTModelInstanceDetails(bindingTemplate.getTModelInstanceDetails(), config, true);
490 
491         }
492 
493         private static void installTModels(EntityManager em, List<org.uddi.api_v3.TModel> apiTModelList, UddiEntityPublisher publisher, String nodeId) throws DispositionReportFaultMessage {
494                 if (apiTModelList != null) {
495                         for (org.uddi.api_v3.TModel apiTModel : apiTModelList) {
496                                 String tModelKey = apiTModel.getTModelKey();
497 
498                                 if (tModelKey.toUpperCase().endsWith(KeyGenerator.KEYGENERATOR_SUFFIX.toUpperCase())) {
499                                         installPublisherKeyGen(em, apiTModel, publisher, nodeId);
500                                 } else {
501                                         org.apache.juddi.model.Tmodel modelTModel = new org.apache.juddi.model.Tmodel();
502                                         apiTModel.setTModelKey(apiTModel.getTModelKey().toLowerCase());
503 
504                                         MappingApiToModel.mapTModel(apiTModel, modelTModel);
505 
506                                         modelTModel.setAuthorizedName(publisher.getAuthorizedName());
507 
508                                         Date now = new Date();
509                                         modelTModel.setCreated(now);
510                                         modelTModel.setModified(now);
511                                         modelTModel.setModifiedIncludingChildren(now);
512                                         modelTModel.setNodeId(nodeId);
513 
514                                         em.persist(modelTModel);
515 
516                                         SaveTModel stm = new SaveTModel();
517                                         stm.getTModel().add(apiTModel);
518                                         ReplicationNotifier.enqueue(UDDIPublicationImpl.getChangeRecord(modelTModel, apiTModel, nodeId));
519                                 }
520 
521                         }
522                 }
523 
524         }
525 
526         private static void installRootPublisherKeyGen(EntityManager em, TModel rootTModelKeyGen, String rootPartition, UddiEntityPublisher publisher, String nodeId)
527                 throws DispositionReportFaultMessage {
528 
529                 rootTModelKeyGen.setTModelKey(rootPartition + KeyGenerator.PARTITION_SEPARATOR + KeyGenerator.KEYGENERATOR_SUFFIX);
530 
531                 installPublisherKeyGen(em, rootTModelKeyGen, publisher, nodeId);
532         }
533 
534         private static void installPublisherKeyGen(EntityManager em, TModel apiTModel, UddiEntityPublisher publisher, String nodeId) throws DispositionReportFaultMessage {
535 
536                 org.apache.juddi.model.Tmodel modelTModel = new org.apache.juddi.model.Tmodel();
537                 MappingApiToModel.mapTModel(apiTModel, modelTModel);
538 
539                 modelTModel.setAuthorizedName(publisher.getAuthorizedName());
540 
541                 Date now = new Date();
542                 modelTModel.setCreated(now);
543                 modelTModel.setModified(now);
544                 modelTModel.setModifiedIncludingChildren(now);
545                 modelTModel.setNodeId(nodeId);
546 
547                 em.persist(modelTModel);
548 
549         }
550 
551         private static List<String> getPublishers(Configuration config) throws ConfigurationException {
552                 List<String> publishers = new ArrayList<String>();
553                 String basePath = JUDDI_CUSTOM_INSTALL_DATA_DIR;
554                 URL url = ClassUtil.getResource(JUDDI_CUSTOM_INSTALL_DATA_DIR, Install.class);
555                 if (url == null) {
556                         url = ClassUtil.getResource(JUDDI_INSTALL_DATA_DIR, Install.class);
557                         basePath = JUDDI_INSTALL_DATA_DIR;
558                 }
559 
560                 String path = null;
561 
562                 try {
563                         path = url.toURI().getSchemeSpecificPart();
564                 } catch (URISyntaxException e) {
565                         throw new ConfigurationException(e);
566                 }
567 
568                 File dir = new File(path);
569                 String rootPublisherStr = config.getString(Property.JUDDI_ROOT_PUBLISHER);
570                 if (dir.exists()) {
571                         log.debug("Discovering the Publisher XML data files in directory: " + path);
572                         File[] files = dir.listFiles(new PublisherFileFilter());
573                         if (files!=null)
574                                 for (File f : files) {
575                                         String publisher = f.getName().substring(0, f.getName().indexOf(FILE_PUBLISHER));
576                                         if (!rootPublisherStr.equalsIgnoreCase(publisher)) {
577                                                 publishers.add(publisher);
578                                         }
579                                 }
580                 } else {
581                         String[] paths = {};
582                         Enumeration<JarEntry> en = null;
583                         JarFile jf = null;
584                         try {
585 
586                                 if (path.indexOf("!") > 0) {
587                                         paths = path.split("!");
588                                         jf = new JarFile(new File(new URI(paths[0])));
589                                         en = jf.entries();
590                                 } else {
591                                         // Handle Windows / jboss-5.1.0 case
592                                         if (path.indexOf(".jar") > 0) {
593                                                 paths = path.split(".jar");
594                                                 paths[0] = paths[0] + ".jar";
595                                                 File temp = new File(paths[0]);
596                                                 if (temp.exists()) {
597                                                         jf = new JarFile(temp);
598                                                         en = jf.entries();
599                                                 }
600                                         }
601                                 }
602                                 if (paths.length > 0) {
603                                         log.debug("Discovering the Publisher XML data files in jar: " + paths[0]);
604                                         while (en != null && en.hasMoreElements()) {
605                                                 String name = en.nextElement().getName();
606                                                 if (name.endsWith(FILE_PUBLISHER)) {
607                                                         log.debug("Found publisher file=" + name);
608                                                         String publisher = name.substring(basePath.length(), name.indexOf(FILE_PUBLISHER));
609                                                         if (!rootPublisherStr.equalsIgnoreCase(publisher)) {
610                                                                 publishers.add(publisher);
611                                                         }
612                                                 }
613                                         }
614                                 } else {
615                                         log.info("No custom configuration files where found in " + path);
616                                 }
617                                 if (jf != null) {
618                                         jf.close();
619                                 }
620 
621                         } catch (IOException e) {
622                                 throw new ConfigurationException(e);
623                         } catch (URISyntaxException e) {
624                                 throw new ConfigurationException(e);
625                         }
626                 }
627                 return publishers;
628         }
629 
630         private static Object buildInstallEntityAlt(final String fileName, Class outputtype, Configuration config) throws JAXBException, IOException, ConfigurationException {
631                 InputStream resourceStream = null;
632 
633                 // First try the custom install directory
634                 URL url = ClassUtil.getResource(JUDDI_CUSTOM_INSTALL_DATA_DIR + fileName, Install.class);
635                 if (url != null) {
636                         resourceStream = url.openStream();
637                 }
638 
639                 // If the custom install directory doesn't exist, then use the standard install directory where the resource is guaranteed to exist.
640                 if (resourceStream == null) {
641                         url = ClassUtil.getResource(JUDDI_INSTALL_DATA_DIR + fileName, Install.class);
642                         if (url != null) {
643                                 resourceStream = url.openStream();
644                         }
645                         // If file still does not exist then return null;
646                         if (url == null || resourceStream == null) {
647                                 if (fileName.endsWith(FILE_PUBLISHER)) {
648                                         throw new ConfigurationException("Could not locate " + JUDDI_INSTALL_DATA_DIR + fileName);
649                                 } else {
650                                         log.debug("Could not locate: " + url);
651                                 }
652                                 return null;
653                         }
654                 }
655                 log.info("Loading the content of file: " + url);
656                 StringBuilder xml = new StringBuilder();
657                 byte[] b = new byte[4096];
658                 for (int n; (n = resourceStream.read(b)) != -1;) {
659                         xml.append(new String(b, 0, n, AuthenticatedService.UTF8));
660                 }
661                 log.debug("inserting: " + xml.toString());
662                 StringReader reader = new StringReader(xml.toString());
663              
664                Object obj= XmlUtils.unmarshal(reader, outputtype);
665                reader.close();
666                return obj;
667         }
668 
669         private static Object buildInstallEntity(final String fileName, String packageName, Configuration config) throws JAXBException, IOException, ConfigurationException, XMLStreamException {
670                 InputStream resourceStream = null;
671 
672                 // First try the custom install directory
673                 URL url = ClassUtil.getResource(JUDDI_CUSTOM_INSTALL_DATA_DIR + fileName, Install.class);
674                 if (url != null) {
675                         resourceStream = url.openStream();
676                 }
677 
678                 // If the custom install directory doesn't exist, then use the standard install directory where the resource is guaranteed to exist.
679                 if (resourceStream == null) {
680                         url = ClassUtil.getResource(JUDDI_INSTALL_DATA_DIR + fileName, Install.class);
681                         if (url != null) {
682                                 resourceStream = url.openStream();
683                         }
684                         // If file still does not exist then return null;
685                         if (url == null || resourceStream == null) {
686                                 if (fileName.endsWith(FILE_PUBLISHER)) {
687                                         throw new ConfigurationException("Could not locate " + JUDDI_INSTALL_DATA_DIR + fileName);
688                                 } else {
689                                         log.debug("Could not locate: " + url);
690                                 }
691                                 return null;
692                         }
693                 }
694                 log.info("Loading the content of file: " + url);
695                 StringBuilder xml = new StringBuilder();
696                 byte[] b = new byte[4096];
697                 for (int n; (n = resourceStream.read(b)) != -1;) {
698                         xml.append(new String(b, 0, n, AuthenticatedService.UTF8));
699                 }
700                 log.debug("inserting: " + xml.toString());
701                 StringReader reader = new StringReader(xml.toString());
702 
703                 Object obj= XmlUtils.unmarshal(reader, packageName);
704                 reader.close();
705                 return obj;
706         }
707 
708         /**
709          * Public convenience method that allows one to retrieve the node
710          * business entity (perhaps to display during an install process, or
711          * even to initiate the install process).
712          *
713          * @param businessKey
714          * @return BusinessEntity Object
715          * @throws DispositionReportFaultMessage
716          */
717         public static org.uddi.api_v3.BusinessEntity getNodeBusinessEntity(String businessKey) throws DispositionReportFaultMessage {
718                 UDDIInquiryImpl inquiry = new UDDIInquiryImpl();
719 
720                 org.uddi.api_v3.GetBusinessDetail gbd = new org.uddi.api_v3.GetBusinessDetail();
721                 gbd.getBusinessKey().add(businessKey);
722 
723                 org.uddi.api_v3.BusinessDetail bd = inquiry.getBusinessDetail(gbd);
724                 if (bd != null) {
725                         List<org.uddi.api_v3.BusinessEntity> beList = bd.getBusinessEntity();
726                         if (beList != null && beList.size() > 0) {
727                                 return beList.get(0);
728                         }
729                 }
730 
731                 return new org.uddi.api_v3.BusinessEntity();
732         }
733 
734         /**
735          * Public convenience method that allows one to install additional
736          * TModels via a SaveTModel structure.
737          *
738          * @param em - the entity manager to a juddi model
739          * @param fileName - name of SaveTModel xml file
740          * @param publisher - the publisher structure that owns the tModels
741          * @param nodeId - the node id of the custodial node
742          * @throws JAXBException
743          * @throws DispositionReportFaultMessage
744          * @throws IOException
745          * @throws ConfigurationException
746          */
747         public static void installSaveTModel(EntityManager em, String fileName, UddiEntityPublisher publisher, String nodeId, Configuration config)
748                 throws JAXBException, DispositionReportFaultMessage, IOException, ConfigurationException, XMLStreamException {
749 
750                 SaveTModel apiSaveTModel = (SaveTModel) buildInstallEntity(fileName, "org.uddi.api_v3", config);
751                 if (apiSaveTModel != null) {
752                         installTModels(em, apiSaveTModel.getTModel(), publisher, nodeId);
753                 }
754         }
755 
756         /**
757          * Public convenience method that allows one to install additional
758          * Publishers via a Publisher structure.
759          *
760          * @param em - the entity manager to the juddi model
761          * @param fileName - name of Publisher xml file
762          * @return UddiEntityPublisher object, can be any UDDIEntity
763          * @throws JAXBException
764          * @throws DispositionReportFaultMessage
765          * @throws IOException
766          * @throws ConfigurationException
767          */
768         public static UddiEntityPublisher installPublisher(EntityManager em, String fileName, Configuration config)
769                 throws JAXBException, DispositionReportFaultMessage, IOException, ConfigurationException, XMLStreamException {
770 
771                 org.apache.juddi.api_v3.Publisher apiPub = (org.apache.juddi.api_v3.Publisher) buildInstallEntity(fileName, "org.apache.juddi.api_v3", config);
772                 if (apiPub == null) {
773                         return null;
774                 }
775                 org.apache.juddi.model.Publisher modelPub = new org.apache.juddi.model.Publisher();
776                 MappingApiToModel.mapPublisher(apiPub, modelPub);
777                 em.persist(modelPub);
778                 return modelPub;
779         }
780 
781         public static org.uddi.repl_v3.ReplicationConfiguration applyReplicationTokenChanges(org.uddi.repl_v3.ReplicationConfiguration replicationCfg, Configuration config, String thisnode) {
782                 log.info("replacing tokens on repl config");
783                 if (replicationCfg == null) {
784                         return null;
785                 }
786                 //apply any token replacements
787                 for (Operator op : replicationCfg.getOperator()) {
788                         op.setOperatorNodeID(op.getOperatorNodeID().replace("${juddi.nodeId}", thisnode));
789                         op.setSoapReplicationURL(op.getSoapReplicationURL().replace("${juddi.server.baseurlsecure}", config.getString("juddi.server.baseurlsecure")));
790                         op.setSoapReplicationURL(op.getSoapReplicationURL().replace("${juddi.server.baseurl}", config.getString("juddi.server.baseurl")));
791                 }
792                 if (replicationCfg.getCommunicationGraph() != null) {
793                         for (int i = 0; i < replicationCfg.getCommunicationGraph().getNode().size(); i++) {
794                                 replicationCfg.getCommunicationGraph().getNode().set(i, replicationCfg.getCommunicationGraph().getNode().get(i).replace("${juddi.nodeId}", thisnode));
795 
796                         }
797                         for (int i = 0; i < replicationCfg.getCommunicationGraph().getEdge().size(); i++) {
798                                 replicationCfg.getCommunicationGraph().getEdge().get(i).setMessageSender(replicationCfg.getCommunicationGraph().getEdge().get(i).getMessageSender().replace("${juddi.nodeId}", thisnode));
799                                 replicationCfg.getCommunicationGraph().getEdge().get(i).setMessageReceiver(replicationCfg.getCommunicationGraph().getEdge().get(i).getMessageReceiver().replace("${juddi.nodeId}", thisnode));
800                                 for (int k = 0; k < replicationCfg.getCommunicationGraph().getEdge().get(i).getMessageReceiverAlternate().size(); k++) {
801                                         replicationCfg.getCommunicationGraph().getEdge().get(i).getMessageReceiverAlternate().set(k, replicationCfg.getCommunicationGraph().getEdge().get(i).getMessageReceiverAlternate().get(k).replace("${juddi.nodeId}", thisnode));
802                                 }
803                         }
804                 }
805 
806                 for (Operator op : replicationCfg.getOperator()) {
807                         op.setOperatorNodeID(op.getOperatorNodeID().replace("${juddi.nodeId}", thisnode));
808                 }
809                 log.info("replacing tokens on repl config, done");
810                 return replicationCfg;
811         }
812 
813         private static void installReplicationConfiguration(EntityManager em, org.uddi.repl_v3.ReplicationConfiguration replicationCfg, Configuration config, String thisnode) throws DispositionReportFaultMessage, ConfigurationException {
814                 replicationCfg = applyReplicationTokenChanges(replicationCfg, config, thisnode);
815                 new ValidateReplication(null, thisnode).validateSetReplicationNodes(replicationCfg, em, thisnode, config);
816 
817                 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddkkmmZ");
818                 replicationCfg.setTimeOfConfigurationUpdate(sdf.format(new Date()));
819 
820                 org.apache.juddi.model.ReplicationConfiguration model = new ReplicationConfiguration();
821 
822                 MappingApiToModel.mapReplicationConfiguration(replicationCfg, model, em);
823 
824                 model.setSerialNumber(System.currentTimeMillis());
825 
826                 org.apache.juddi.model.ReplicationConfiguration oldstuff = null;
827                 // logger.info(publisher.getAuthorizedName() + " is setting the replication config from " + getRequestorsIPAddress());// + " " + sw.toString());
828                 try {
829                         oldstuff = (ReplicationConfiguration) em.createQuery("select c FROM ReplicationConfiguration c order by c.serialNumber desc").getSingleResult();
830                 } catch (Exception ex) {
831                 }
832                 if (oldstuff != null) {
833                         em.remove(oldstuff);
834                 }
835                 em.persist(model);
836         }
837 
838 }