1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.exchangesimple;
35
36 import info.magnolia.cms.beans.config.ContentRepository;
37 import info.magnolia.cms.core.Content;
38 import info.magnolia.cms.core.HierarchyManager;
39 import info.magnolia.cms.core.ItemType;
40 import info.magnolia.cms.core.MetaData;
41 import info.magnolia.cms.core.Path;
42 import info.magnolia.cms.core.SystemProperty;
43 import info.magnolia.cms.core.version.ContentVersion;
44 import info.magnolia.cms.exchange.ExchangeException;
45 import info.magnolia.cms.exchange.Subscriber;
46 import info.magnolia.cms.exchange.Subscription;
47 import info.magnolia.cms.exchange.Syndicator;
48 import info.magnolia.cms.security.AccessDeniedException;
49 import info.magnolia.cms.security.User;
50 import info.magnolia.cms.util.ContentUtil;
51 import info.magnolia.cms.util.Rule;
52 import info.magnolia.cms.util.RuleBasedContentFilter;
53 import info.magnolia.context.MgnlContext;
54 import info.magnolia.logging.AuditLoggingUtil;
55
56 import java.io.File;
57 import java.io.FileInputStream;
58 import java.io.FileOutputStream;
59 import java.io.IOException;
60 import java.io.OutputStream;
61 import java.io.UnsupportedEncodingException;
62 import java.net.HttpURLConnection;
63 import java.net.MalformedURLException;
64 import java.net.URL;
65 import java.net.URLConnection;
66 import java.net.URLEncoder;
67 import java.util.Iterator;
68 import java.util.List;
69 import java.util.zip.GZIPOutputStream;
70
71 import javax.jcr.RepositoryException;
72 import javax.jcr.Session;
73
74 import org.apache.commons.codec.binary.Base64;
75 import org.apache.commons.io.IOUtils;
76 import org.apache.commons.lang.StringUtils;
77 import org.apache.xml.serialize.OutputFormat;
78 import org.apache.xml.serialize.XMLSerializer;
79 import org.jdom.Document;
80 import org.jdom.Element;
81 import org.jdom.output.XMLOutputter;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
84 import org.xml.sax.InputSource;
85 import org.xml.sax.SAXException;
86 import org.xml.sax.XMLReader;
87 import org.xml.sax.helpers.XMLReaderFactory;
88
89 import EDU.oswego.cs.dl.util.concurrent.Sync;
90
91
92
93
94
95
96 public abstract class BaseSyndicatorImpl implements Syndicator {
97 private static final Logger log = LoggerFactory.getLogger(BaseSyndicatorImpl.class);
98
99
100
101
102 public static final String DEFAULT_HANDLER = ".magnolia/activation";
103
104 public static final String PARENT_PATH = "mgnlExchangeParentPath";
105
106 public static final String MAPPED_PARENT_PATH = "mgnlExchangeMappedParent";
107
108
109
110
111 public static final String PATH = "mgnlExchangePath";
112
113 public static final String NODE_UUID = "mgnlExchangeNodeUUID";
114
115 public static final String REPOSITORY_NAME = "mgnlExchangeRepositoryName";
116
117 public static final String WORKSPACE_NAME = "mgnlExchangeWorkspaceName";
118
119 public static final String VERSION_NAME = "mgnlExchangeVersionName";
120
121
122
123
124 public static final String RESOURCE_MAPPING_FILE = "mgnlExchangeResourceMappingFile";
125
126 public static final String UTF8_STATUS = "mgnlUTF8Status";
127
128
129
130
131
132
133 public static final String SIBLINGS_ROOT_ELEMENT = "NodeSiblings";
134
135 public static final String SIBLINGS_ELEMENT = "sibling";
136
137 public static final String SIBLING_UUID = "siblingUUID";
138
139 public static final String RESOURCE_MAPPING_FILE_ELEMENT = "File";
140
141 public static final String RESOURCE_MAPPING_NAME_ATTRIBUTE = "name";
142
143 public static final String RESOURCE_MAPPING_UUID_ATTRIBUTE = "contentUUID";
144
145 public static final String RESOURCE_MAPPING_ID_ATTRIBUTE = "resourceId";
146
147 public static final String RESOURCE_MAPPING_ROOT_ELEMENT = "Resources";
148
149 public static final String ACTION = "mgnlExchangeAction";
150
151 public static final String ACTIVATE = "activate";
152
153 public static final String DEACTIVATE = "deactivate";
154
155 public static final String COMMIT = "commit";
156
157 public static final String ROLLBACK = "rollback";
158
159 public static final String AUTHORIZATION = "Authorization";
160
161 public static final String AUTH_CREDENTIALS= "mgnlUserPSWD";
162
163 public static final String AUTH_USER = "mgnlUserId";
164
165 public static final String CONTENT_FILTER_RULE = "mgnlExchangeFilterRule";
166
167 public static final String ACTIVATION_SUCCESSFUL = "sa_success";
168
169 public static final String ACTIVATION_FAILED = "sa_failed";
170
171 public static final String ACTIVATION_ATTRIBUTE_STATUS = "sa_attribute_status";
172
173 public static final String ACTIVATION_ATTRIBUTE_MESSAGE = "sa_attribute_message";
174
175 public static final String ACTIVATION_ATTRIBUTE_VERSION = "sa_attribute_version";
176
177
178
179
180
181
182
183 protected static void executeInPool(Runnable job) throws ExchangeException {
184 try {
185 ThreadPool.getInstance().execute(job);
186 } catch (InterruptedException e) {
187
188
189
190
191 String message = "could not execute job in pool";
192 log.error(message, e);
193 throw new ExchangeException(message, e);
194 }
195 }
196
197
198
199
200
201
202
203
204
205
206 protected static void acquireIgnoringInterruption(Sync latch) {
207 try {
208 latch.acquire();
209 } catch (InterruptedException e) {
210
211 acquireIgnoringInterruption(latch);
212
213 Thread.currentThread().interrupt();
214 }
215 }
216
217 protected String repositoryName;
218
219 protected String workspaceName;
220
221 protected String parent;
222
223 protected Content.ContentFilter contentFilter;
224
225 protected Rule contentFilterRule;
226
227 protected User user;
228
229 protected String basicCredentials;
230
231
232
233
234
235
236
237
238
239 public void init(User user, String repositoryName, String workspaceName, Rule rule) {
240 this.user = user;
241 this.basicCredentials = "Basic "
242 + new String(Base64.encodeBase64((this.user.getName() + ":" + this.user.getPassword()).getBytes()));
243 this.contentFilter = new RuleBasedContentFilter(rule);
244 this.contentFilterRule = rule;
245 this.repositoryName = repositoryName;
246 this.workspaceName = workspaceName;
247 }
248
249
250
251
252
253
254
255
256
257 public void activate(String parent, Content content) throws ExchangeException, RepositoryException {
258 this.activate(parent, content, null);
259 }
260
261
262
263
264
265
266
267
268
269
270
271 public void activate(String parent, Content content, List<String> orderBefore) throws ExchangeException, RepositoryException {
272 this.activate(null, parent, content, orderBefore);
273 }
274
275
276
277
278
279
280
281
282
283
284 public void activate(Subscriber subscriber, String parent, Content content) throws ExchangeException, RepositoryException {
285 this.activate(subscriber, parent, content, null);
286 }
287
288
289
290
291
292
293
294
295
296
297
298 public void activate(Subscriber subscriber, String parent, Content content, List<String> orderBefore) throws ExchangeException, RepositoryException {
299 this.parent = parent;
300 String path = content.getHandle();
301
302 ActivationContent activationContent = null;
303 try {
304 activationContent = this.collect(content, orderBefore);
305 if (null == subscriber) {
306 this.activate(activationContent, path);
307 } else {
308 this.activate(subscriber, activationContent, path);
309 }
310 if (Boolean.parseBoolean(activationContent.getproperty(ItemType.DELETED_NODE_MIXIN))) {
311 final HierarchyManager hm = content.getHierarchyManager();
312 String uuid = content.getUUID();
313 if (StringUtils.isNotBlank(uuid)) {
314 if (content instanceof ContentVersion) {
315
316 content = hm.getContentByUUID(uuid);
317 }
318 Content parentContent = content.getParent();
319 content.delete();
320 parentContent.save();
321 } else {
322 log.warn("Content {}:{} was already removed.", new String[] {hm.getName(), path});
323 }
324 } else {
325 this.updateActivationDetails(path);
326 }
327 log.info("Exchange: activation succeeded [{}]", path);
328 } catch (Exception e) {
329 if (log.isDebugEnabled()) {
330 log.error("Exchange: activation failed for path:" + ((path != null) ? path : "[null]"), e);
331 long timestamp = System.currentTimeMillis();
332 log.warn("moving files from failed activation to *.failed" + timestamp );
333 Iterator<File> keys = activationContent.getFiles().values().iterator();
334 while (keys.hasNext()) {
335 File f = keys.next();
336 f.renameTo(new File(f.getAbsolutePath()+".failed" + timestamp));
337 }
338 activationContent.getFiles().clear();
339
340 }
341 throw new ExchangeException(e);
342 } finally {
343 log.debug("Cleaning temporary files");
344 cleanTemporaryStore(activationContent);
345 }
346 }
347
348
349
350
351 public abstract void activate(ActivationContent activationContent, String nodePath) throws ExchangeException;
352
353
354
355
356
357 public String activate(Subscriber subscriber, ActivationContent activationContent, String nodePath) throws ExchangeException {
358
359 log.debug("activate");
360 if (null == subscriber) {
361 throw new ExchangeException("Null Subscriber");
362 }
363
364 String parentPath = null;
365
366
367 Subscription subscription = subscriber.getMatchedSubscription(nodePath, this.repositoryName);
368 if (null != subscription) {
369
370 parentPath = this.getMappedPath(this.parent, subscription);
371 activationContent.setProperty(PARENT_PATH, parentPath);
372 } else {
373 log.debug("Exchange : subscriber [{}] is not subscribed to {}", subscriber.getName(), nodePath);
374 return "not subscribed";
375 }
376 log.debug("Exchange : sending activation request to {} with user {}", subscriber.getName(), this.user.getName());
377
378 URLConnection urlConnection = null;
379 String versionName = null;
380 try {
381 urlConnection = prepareConnection(subscriber, getActivationURL(subscriber));
382 this.addActivationHeaders(urlConnection, activationContent);
383
384 Transporter.transport((HttpURLConnection) urlConnection, activationContent);
385
386 String status = urlConnection.getHeaderField(ACTIVATION_ATTRIBUTE_STATUS);
387 versionName = urlConnection.getHeaderField(ACTIVATION_ATTRIBUTE_VERSION);
388
389
390 if (StringUtils.equals(status, ACTIVATION_FAILED)) {
391 String message = urlConnection.getHeaderField(ACTIVATION_ATTRIBUTE_MESSAGE);
392 throw new ExchangeException("Message received from subscriber: " + message);
393 }
394 urlConnection.getContent();
395 log.debug("Exchange : activation request sent to {}", subscriber.getName());
396 }
397 catch (ExchangeException e) {
398 throw e;
399 }
400 catch (IOException e) {
401 log.debug("Failed to transport following activated content {" + StringUtils.join(activationContent.getProperties().keySet().iterator(), ',') + "} due to " + e.getMessage(), e);
402 String url = (urlConnection == null ? null : urlConnection.getURL().toString());
403 url = stripPasswordFromUrl(url);
404
405 throw new ExchangeException("Not able to send the activation request [" + url + "]: " + e.getMessage(), e);
406 }
407 catch (Exception e) {
408 throw new ExchangeException(e);
409 }
410 return versionName;
411 }
412
413 protected static String stripPasswordFromUrl(String escapedUrl) {
414 if (escapedUrl != null) {
415 int idx = escapedUrl.indexOf("mgnlUserPSWD");
416 if (idx > 0) {
417 int endIdx = escapedUrl.indexOf("&", idx);
418 if (endIdx > 0) {
419 escapedUrl = escapedUrl.substring(0, idx) + escapedUrl.substring(endIdx + 1);
420 } else {
421 escapedUrl = escapedUrl.substring(0, idx - 1);
422 }
423 }
424 }
425 return escapedUrl;
426 }
427
428
429
430
431
432 protected void cleanTemporaryStore(ActivationContent activationContent) {
433 if (activationContent == null) {
434 log.debug("Clean temporary store - nothing to do");
435 return;
436 }
437 if (log.isDebugEnabled()) {
438 log.debug("Debugging is enabled. Keeping temporary files in store for debugging purposes. Clean the store manually once done with debugging.");
439 return;
440 }
441
442 Iterator<String> keys = activationContent.getFiles().keySet().iterator();
443 while (keys.hasNext()) {
444 String key = keys.next();
445 log.debug("Removing temporary file {}", key);
446 activationContent.getFile(key).delete();
447 }
448 }
449
450 public synchronized void deactivate(String path) throws ExchangeException, RepositoryException {
451 final Content node = getHierarchyManager().getContent(path);
452 deactivate(node);
453 }
454
455
456
457
458
459
460 public synchronized void deactivate(Content node) throws ExchangeException, RepositoryException {
461 String nodeUUID = node.getUUID();
462 String path = node.getHandle();
463 this.doDeactivate(nodeUUID, path);
464 updateDeactivationDetails(nodeUUID);
465 }
466
467
468
469
470
471
472
473 public synchronized void deactivate(Subscriber subscriber, Content node) throws ExchangeException, RepositoryException {
474 String nodeUUID = node.getUUID();
475 String path = node.getHandle();
476 this.doDeactivate(subscriber, nodeUUID, path);
477 updateDeactivationDetails(nodeUUID);
478 }
479
480
481
482
483 public abstract void doDeactivate(String nodeUUID, String nodePath) throws ExchangeException;
484
485
486
487
488
489
490 public abstract String doDeactivate(Subscriber subscriber, String nodeUUID, String nodePath) throws ExchangeException;
491
492
493
494
495
496 protected String getDeactivationURL(Subscriber subscriberInfo) {
497 return getActivationURL(subscriberInfo);
498 }
499
500
501
502
503
504 protected void addDeactivationHeaders(URLConnection connection, String nodeUUID) {
505 connection.addRequestProperty(REPOSITORY_NAME, this.repositoryName);
506 connection.addRequestProperty(WORKSPACE_NAME, this.workspaceName);
507 if (nodeUUID != null) {
508 connection.addRequestProperty(NODE_UUID, nodeUUID);
509 }
510 connection.addRequestProperty(ACTION, DEACTIVATE);
511 }
512
513
514
515
516 protected String getActivationURL(Subscriber subscriberInfo) {
517 final String url = subscriberInfo.getURL();
518 if (!url.endsWith("/")) {
519 return url + "/" + DEFAULT_HANDLER;
520 }
521 return url + DEFAULT_HANDLER;
522 }
523
524
525
526
527 protected void addActivationHeaders(URLConnection connection, ActivationContent activationContent) {
528 Iterator<String> headerKeys = activationContent.getProperties().keySet().iterator();
529 while (headerKeys.hasNext()) {
530 String key = headerKeys.next();
531 String value = activationContent.getproperty(key);
532 if(SystemProperty.getBooleanProperty(SystemProperty.MAGNOLIA_UTF8_ENABLED)) {
533 try {
534 value = URLEncoder.encode(value, "UTF-8");
535 }
536 catch (UnsupportedEncodingException e) {
537
538 }
539 }
540 connection.setRequestProperty(key, value);
541 }
542 }
543
544
545
546
547 protected void updateActivationDetails(String path) throws RepositoryException {
548
549 Content page = getSystemHierarchyManager().getContent(path);
550 updateMetaData(page, ACTIVATE);
551 page.save();
552 AuditLoggingUtil.log(AuditLoggingUtil.ACTION_ACTIVATE, this.workspaceName, page.getItemType(), path );
553 }
554
555
556
557
558 protected void updateDeactivationDetails(String nodeUUID) throws RepositoryException {
559
560 Content page = getSystemHierarchyManager().getContentByUUID(nodeUUID);
561 updateMetaData(page, DEACTIVATE);
562 page.save();
563 AuditLoggingUtil.log(AuditLoggingUtil.ACTION_DEACTIVATE, this.workspaceName, page.getItemType(), page.getHandle() );
564 }
565
566
567 private HierarchyManager getHierarchyManager() {
568 return MgnlContext.getHierarchyManager(this.repositoryName, this.workspaceName);
569 }
570
571 private HierarchyManager getSystemHierarchyManager() {
572 return MgnlContext.getSystemContext().getHierarchyManager(this.repositoryName, this.workspaceName);
573 }
574
575
576
577
578
579 protected void updateMetaData(Content node, String type) throws AccessDeniedException {
580
581 MetaData md = node.getMetaData();
582 if (type.equals(ACTIVATE)) {
583 md.setActivated();
584 }
585 else {
586 md.setUnActivated();
587 }
588 md.setActivatorId(this.user.getName());
589 md.setLastActivationActionDate();
590
591 Iterator<Content> children;
592 if (type.equals(ACTIVATE)) {
593
594 children = node.getChildren(this.contentFilter).iterator();
595 }
596 else {
597
598 children = node.getChildren(ContentUtil.EXCLUDE_META_DATA_CONTENT_FILTER).iterator();
599 }
600
601 while (children.hasNext()) {
602 Content child = children.next();
603 this.updateMetaData(child, type);
604 }
605
606
607 }
608
609
610
611
612
613 protected ActivationContent collect(Content node, List<String> orderBefore) throws Exception {
614
615 File resourceFile = File.createTempFile("resources", ".xml", Path.getTempDirectory());
616
617 ActivationContent activationContent = new ActivationContent();
618
619 activationContent.addProperty(PARENT_PATH, this.parent);
620 activationContent.addProperty(WORKSPACE_NAME, this.workspaceName);
621 activationContent.addProperty(REPOSITORY_NAME, this.repositoryName);
622 activationContent.addProperty(RESOURCE_MAPPING_FILE, resourceFile.getName());
623 activationContent.addProperty(ACTION, ACTIVATE);
624 activationContent.addProperty(CONTENT_FILTER_RULE, this.contentFilterRule.toString());
625 activationContent.addProperty(NODE_UUID, node.getUUID());
626 activationContent.addProperty(UTF8_STATUS, SystemProperty.getProperty(SystemProperty.MAGNOLIA_UTF8_ENABLED));
627
628
629 Document document = new Document();
630 Element root = new Element(RESOURCE_MAPPING_ROOT_ELEMENT);
631 document.setRootElement(root);
632
633 addOrderingInfo(root, orderBefore);
634
635 this.addResources(root, node.getWorkspace().getSession(), node, this.contentFilter, activationContent);
636 XMLOutputter outputter = new XMLOutputter();
637 outputter.output(document, new FileOutputStream(resourceFile));
638
639 activationContent.addFile(resourceFile.getName(), resourceFile);
640
641
642 activationContent.addProperty(ItemType.DELETED_NODE_MIXIN, "" + node.hasMixin(ItemType.DELETED_NODE_MIXIN));
643
644 return activationContent;
645 }
646
647
648
649
650
651
652 protected void addOrderingInfo(Element root, List<String> orderBefore) {
653
654 Element siblingRoot = new Element(SIBLINGS_ROOT_ELEMENT);
655 root.addContent(siblingRoot);
656 if (orderBefore == null) {
657 return;
658 }
659 Iterator<String> siblings = orderBefore.iterator();
660 while (siblings.hasNext()) {
661 String uuid = siblings.next();
662 Element e = new Element(SIBLINGS_ELEMENT);
663 e.setAttribute(SIBLING_UUID, uuid);
664 siblingRoot.addContent(e);
665 }
666 }
667
668 protected void addResources(Element resourceElement, Session session, final Content content, Content.ContentFilter filter, ActivationContent activationContent) throws IOException, RepositoryException, SAXException, Exception {
669 final String workspaceName = content.getWorkspace().getName();
670 log.debug("Preparing content {}:{} for publishing.", new String[] {workspaceName, content.getHandle()});
671 final String uuid = content.getUUID();
672
673 File file = File.createTempFile("exchange_" + uuid, ".xml.gz", Path.getTempDirectory());
674 GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new FileOutputStream(file));
675
676
677 if (content.isNodeType("nt:frozenNode") || workspaceName.equals(ContentRepository.VERSION_STORE)) {
678 XMLReader elementfilter = new FrozenElementFilter(XMLReaderFactory
679 .createXMLReader(org.apache.xerces.parsers.SAXParser.class.getName()));
680 ((FrozenElementFilter) elementfilter).setNodeName(content.getName());
681
682
683
684 boolean noRecurse = !content.isNodeType(ItemType.NT_FILE);
685 exportAndParse(session, content, elementfilter, gzipOutputStream, noRecurse);
686 } else {
687
688
689
690 if (content.isNodeType(ItemType.NT_FILE)) {
691 session.exportSystemView(content.getJCRNode().getPath(), gzipOutputStream, false, false);
692 } else {
693 session.exportSystemView(content.getJCRNode().getPath(), gzipOutputStream, false, true);
694 }
695 }
696
697 IOUtils.closeQuietly(gzipOutputStream);
698
699 Element element = new Element(RESOURCE_MAPPING_FILE_ELEMENT);
700 element.setAttribute(RESOURCE_MAPPING_NAME_ATTRIBUTE, content.getName());
701 element.setAttribute(RESOURCE_MAPPING_UUID_ATTRIBUTE, uuid);
702 element.setAttribute(RESOURCE_MAPPING_ID_ATTRIBUTE, file.getName());
703 resourceElement.addContent(element);
704
705 activationContent.addFile(file.getName(), file);
706
707 Iterator<Content> children = content.getChildren(filter).iterator();
708 while (children.hasNext()) {
709 Content child = children.next();
710 this.addResources(element, session, child, filter, activationContent);
711 }
712 }
713
714 protected void exportAndParse(Session session, Content content, XMLReader elementfilter, OutputStream os, boolean noRecurse) throws Exception {
715 File tempFile = File.createTempFile("Frozen_"+content.getName(), ".xml");
716 OutputStream tmpFileOutStream = null;
717 FileInputStream tmpFileInStream = null;
718 try {
719 tmpFileOutStream = new FileOutputStream(tempFile);
720
721 session.exportSystemView(content.getJCRNode().getPath(), tmpFileOutStream, false, noRecurse);
722 tmpFileOutStream.flush();
723 tmpFileOutStream.close();
724
725 OutputFormat outputFormat = new OutputFormat();
726 outputFormat.setPreserveSpace(false);
727
728 tmpFileInStream = new FileInputStream(tempFile);
729 elementfilter.setContentHandler(new XMLSerializer(os, outputFormat));
730 elementfilter.parse(new InputSource(tmpFileInStream));
731 tmpFileInStream.close();
732 } catch (Throwable t) {
733 log.error("Failed to parse XML using FrozenElementFilter",t);
734 throw new Exception(t);
735 } finally {
736 IOUtils.closeQuietly(tmpFileInStream);
737 IOUtils.closeQuietly(tmpFileOutStream);
738 tempFile.delete();
739 }
740 }
741
742
743
744
745 protected String getMappedPath(String path, Subscription subscription) {
746 String toURI = subscription.getToURI();
747 if (null != toURI) {
748 String fromURI = subscription.getFromURI();
749
750 fromURI = StringUtils.removeEnd(fromURI, "/");
751 toURI = StringUtils.removeEnd(toURI, "/");
752
753 path = path.replaceFirst(fromURI, toURI);
754 if (path.equals("")) {
755 path = "/";
756 }
757 }
758 return path;
759 }
760
761 protected URLConnection prepareConnection(Subscriber subscriber, String urlString) throws ExchangeException {
762
763
764
765 try {
766 String authMethod = subscriber.getAuthenticationMethod();
767
768 if (authMethod != null && "form".equalsIgnoreCase(authMethod)) {
769 urlString += (urlString.indexOf('?') > 0 ? "&" : "?") + AUTH_USER + "=" + this.user.getName();
770 urlString += "&" + AUTH_CREDENTIALS + "=" + this.user.getPassword();
771 }
772 URL url = new URL(urlString);
773 URLConnection urlConnection = url.openConnection();
774 urlConnection.setConnectTimeout(subscriber.getConnectTimeout());
775 urlConnection.setReadTimeout(subscriber.getReadTimeout());
776
777 if (authMethod == null || "basic".equalsIgnoreCase(authMethod)) {
778 urlConnection.setRequestProperty(AUTHORIZATION, this.basicCredentials);
779 } else if (!"form".equalsIgnoreCase(subscriber.getAuthenticationMethod())) {
780 log.info("Unknown Authentication method for deactivation: " + subscriber.getAuthenticationMethod());
781 }
782
783 return urlConnection;
784 } catch (MalformedURLException e) {
785 throw new ExchangeException("Incorrect URL for subscriber " + subscriber + "[" + stripPasswordFromUrl(urlString) + "]");
786 } catch (IOException e) {
787 throw new ExchangeException("Not able to send the activation request [" + stripPasswordFromUrl(urlString) + "]: " + e.getMessage());
788 } catch (Exception e) {
789 throw new ExchangeException(e);
790 }
791 }
792
793
794 }