/** * See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Board of Regents of the University of Wisconsin System * licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a * copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * */ package com.microsoft.exchange.impl; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; import org.springframework.ws.client.core.WebServiceMessageCallback; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; import org.springframework.ws.soap.client.SoapFaultClientException; import org.springframework.ws.soap.client.core.SoapActionCallback; import org.springframework.ws.transport.WebServiceMessageSender; import org.springframework.ws.transport.http.HttpComponentsMessageSender; import com.microsoft.exchange.ExchangeWebServices; import com.microsoft.exchange.exception.ExchangeInvalidUPNRuntimeException; import com.microsoft.exchange.exception.ExchangeWebServicesRuntimeException; import com.microsoft.exchange.messages.AddDelegate; import com.microsoft.exchange.messages.AddDelegateResponse; import com.microsoft.exchange.messages.ConvertId; import com.microsoft.exchange.messages.ConvertIdResponse; import com.microsoft.exchange.messages.CopyFolder; import com.microsoft.exchange.messages.CopyFolderResponse; import com.microsoft.exchange.messages.CopyItem; import com.microsoft.exchange.messages.CopyItemResponse; import com.microsoft.exchange.messages.CreateAttachment; import com.microsoft.exchange.messages.CreateAttachmentResponse; import com.microsoft.exchange.messages.CreateFolder; import com.microsoft.exchange.messages.CreateFolderResponse; import com.microsoft.exchange.messages.CreateItem; import com.microsoft.exchange.messages.CreateItemResponse; import com.microsoft.exchange.messages.CreateManagedFolder; import com.microsoft.exchange.messages.CreateManagedFolderResponse; import com.microsoft.exchange.messages.DeleteAttachment; import com.microsoft.exchange.messages.DeleteAttachmentResponse; import com.microsoft.exchange.messages.DeleteFolder; import com.microsoft.exchange.messages.DeleteFolderResponse; import com.microsoft.exchange.messages.DeleteItem; import com.microsoft.exchange.messages.DeleteItemResponse; import com.microsoft.exchange.messages.EmptyFolder; import com.microsoft.exchange.messages.EmptyFolderResponse; import com.microsoft.exchange.messages.ExpandDL; import com.microsoft.exchange.messages.ExpandDLResponse; import com.microsoft.exchange.messages.FindFolder; import com.microsoft.exchange.messages.FindFolderResponse; import com.microsoft.exchange.messages.FindItem; import com.microsoft.exchange.messages.FindItemResponse; import com.microsoft.exchange.messages.GetAttachment; import com.microsoft.exchange.messages.GetAttachmentResponse; import com.microsoft.exchange.messages.GetDelegate; import com.microsoft.exchange.messages.GetDelegateResponse; import com.microsoft.exchange.messages.GetEvents; import com.microsoft.exchange.messages.GetEventsResponse; import com.microsoft.exchange.messages.GetFolder; import com.microsoft.exchange.messages.GetFolderResponse; import com.microsoft.exchange.messages.GetItem; import com.microsoft.exchange.messages.GetItemResponse; import com.microsoft.exchange.messages.GetServerTimeZones; import com.microsoft.exchange.messages.GetServerTimeZonesResponse; import com.microsoft.exchange.messages.GetUserAvailabilityRequest; import com.microsoft.exchange.messages.GetUserAvailabilityResponse; import com.microsoft.exchange.messages.GetUserOofSettingsRequest; import com.microsoft.exchange.messages.GetUserOofSettingsResponse; import com.microsoft.exchange.messages.MoveFolder; import com.microsoft.exchange.messages.MoveFolderResponse; import com.microsoft.exchange.messages.MoveItem; import com.microsoft.exchange.messages.MoveItemResponse; import com.microsoft.exchange.messages.RemoveDelegate; import com.microsoft.exchange.messages.RemoveDelegateResponse; import com.microsoft.exchange.messages.ResolveNames; import com.microsoft.exchange.messages.ResolveNamesResponse; import com.microsoft.exchange.messages.SendItem; import com.microsoft.exchange.messages.SendItemResponse; import com.microsoft.exchange.messages.SetUserOofSettingsRequest; import com.microsoft.exchange.messages.SetUserOofSettingsResponse; import com.microsoft.exchange.messages.Subscribe; import com.microsoft.exchange.messages.SubscribeResponse; import com.microsoft.exchange.messages.SyncFolderHierarchy; import com.microsoft.exchange.messages.SyncFolderHierarchyResponse; import com.microsoft.exchange.messages.SyncFolderItems; import com.microsoft.exchange.messages.SyncFolderItemsResponse; import com.microsoft.exchange.messages.Unsubscribe; import com.microsoft.exchange.messages.UnsubscribeResponse; import com.microsoft.exchange.messages.UpdateDelegate; import com.microsoft.exchange.messages.UpdateDelegateResponse; import com.microsoft.exchange.messages.UpdateFolder; import com.microsoft.exchange.messages.UpdateFolderResponse; import com.microsoft.exchange.messages.UpdateItem; import com.microsoft.exchange.messages.UpdateItemResponse; /** * Spring {@link WebServiceGatewaySupport} backed implementatoin of {@link ExchangeWebServices}. * * @author Nicholas Blair */ @Component public class ExchangeWebServicesClient extends WebServiceGatewaySupport implements ExchangeWebServices { /** * This appears as the message of a SoapFault in the event the client encounters throttle policy limits. */ protected static final String RETRY_ERROR_MESSAGE = "The server cannot service this request right now. Try again later."; protected static final Log log = LogFactory.getLog(ExchangeWebServicesClient.class); private KeyStore keyStore; private char[] keyStorePassword; private KeyStore trustStore; /** * @param keyStore the keyStore to set */ public void setKeyStore(Resource keyStore) { this.keyStore = getKeystoreFromResource(keyStore, keyStorePassword); } /** * @param trustStore the trustStore to set */ public void setTrustStore(Resource trustStore) { this.trustStore = getKeystoreFromResource(trustStore, keyStorePassword); } /** * @param keyStorePassword the keyStorePassword to set */ public void setKeyStorePassword(char[] keyStorePassword) { this.keyStorePassword = keyStorePassword; } /** * * @param resource * @param password * @return */ protected static KeyStore getKeystoreFromResource(Resource resource, char[] password) { try { KeyStore k = KeyStore.getInstance(KeyStore.getDefaultType()); k.load(resource.getInputStream(), password); log.info("keystore loaded: " +k.toString() +", from:"+ resource.getFilename()); return k; } catch (KeyStoreException e) { throw new IllegalArgumentException("failed to load keystore from " + resource.getDescription(), e); } catch (CertificateException e) { throw new IllegalArgumentException("failed to load keystore from " + resource.getDescription(), e); } catch (IOException e) { throw new IllegalArgumentException("failed to load keystore from " + resource.getDescription(), e); } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException("failed to load keystore from " + resource.getDescription(), e); } } /* (non-Javadoc) * @see org.springframework.ws.client.core.support.WebServiceGatewaySupport#initGateway() */ @Override protected void initGateway() throws Exception { super.initGateway(); WebServiceMessageSender [] senders = getWebServiceTemplate().getMessageSenders(); for(WebServiceMessageSender sender: senders) { if(sender instanceof HttpComponentsMessageSender) { HttpComponentsMessageSender hSender = (HttpComponentsMessageSender) sender; ClientConnectionManager connectionManager = hSender.getHttpClient().getConnectionManager(); SchemeRegistry schemeRegistry = connectionManager.getSchemeRegistry(); SSLSocketFactory sf = new SSLSocketFactory(keyStore, safeToString(keyStorePassword), trustStore); Scheme https = new Scheme("https", 443, sf); schemeRegistry.register(https); log.info("initGateway connection manager with https scheme"); } } } String safeToString(char[] value) { if(value == null) { return null; } return new String(value); } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#resolveNames(com.microsoft.exchange.messages.ResolveNames) */ @Override public ResolveNamesResponse resolveNames(ResolveNames request) { ResolveNamesResponse response = (ResolveNamesResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#expandDL(com.microsoft.exchange.messages.ExpandDL) */ @Override public ExpandDLResponse expandDL(ExpandDL request) { ExpandDLResponse response = (ExpandDLResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#findFolder(com.microsoft.exchange.messages.FindFolder) */ @Override public FindFolderResponse findFolder(FindFolder request) { FindFolderResponse response = (FindFolderResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#findItem(com.microsoft.exchange.messages.FindItem) */ @Override public FindItemResponse findItem(FindItem request) { FindItemResponse response = (FindItemResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#getFolder(com.microsoft.exchange.messages.GetFolder) */ @Override public GetFolderResponse getFolder(GetFolder request) { GetFolderResponse response = (GetFolderResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#convertId(com.microsoft.exchange.messages.ConvertId) */ @Override public ConvertIdResponse convertId(ConvertId request) { ConvertIdResponse response = (ConvertIdResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#createFolder(com.microsoft.exchange.messages.CreateFolder) */ @Override public CreateFolderResponse createFolder(CreateFolder request) { CreateFolderResponse response = (CreateFolderResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#deleteFolder(com.microsoft.exchange.messages.DeleteFolder) */ @Override public DeleteFolderResponse deleteFolder(DeleteFolder request) { DeleteFolderResponse response = (DeleteFolderResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#updateFolder(com.microsoft.exchange.messages.UpdateFolder) */ @Override public UpdateFolderResponse updateFolder(UpdateFolder request) { UpdateFolderResponse response = (UpdateFolderResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#moveFolder(com.microsoft.exchange.messages.MoveFolder) */ @Override public MoveFolderResponse moveFolder(MoveFolder request) { MoveFolderResponse response = (MoveFolderResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#copyFolder(com.microsoft.exchange.messages.CopyFolder) */ @Override public CopyFolderResponse copyFolder(CopyFolder request) { CopyFolderResponse response = (CopyFolderResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#subscribe(com.microsoft.exchange.messages.Subscribe) */ @Override public SubscribeResponse subscribe(Subscribe request) { SubscribeResponse response = (SubscribeResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#unsubscribe(com.microsoft.exchange.messages.Unsubscribe) */ @Override public UnsubscribeResponse unsubscribe(Unsubscribe request) { UnsubscribeResponse response = (UnsubscribeResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#getEvents(com.microsoft.exchange.messages.GetEvents) */ @Override public GetEventsResponse getEvents(GetEvents request) { GetEventsResponse response = (GetEventsResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#syncFolderHierarchy(com.microsoft.exchange.messages.SyncFolderHierarchy) */ @Override public SyncFolderHierarchyResponse syncFolderHierarchy( SyncFolderHierarchy request) { SyncFolderHierarchyResponse response = (SyncFolderHierarchyResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#syncFolderItems(com.microsoft.exchange.messages.SyncFolderItems) */ @Override public SyncFolderItemsResponse syncFolderItems(SyncFolderItems request) { SyncFolderItemsResponse response = (SyncFolderItemsResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#createManagedFolder(com.microsoft.exchange.messages.CreateManagedFolder) */ @Override public CreateManagedFolderResponse createManagedFolder( CreateManagedFolder request) { CreateManagedFolderResponse response = (CreateManagedFolderResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#getItem(com.microsoft.exchange.messages.GetItem) */ @Override public GetItemResponse getItem(GetItem request) { GetItemResponse response = (GetItemResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#createItem(com.microsoft.exchange.messages.CreateItem) */ @Override public CreateItemResponse createItem(CreateItem request) { CreateItemResponse response = (CreateItemResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#deleteItem(com.microsoft.exchange.messages.DeleteItem) */ @Override public DeleteItemResponse deleteItem(DeleteItem request) { DeleteItemResponse response = (DeleteItemResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#updateItem(com.microsoft.exchange.messages.UpdateItem) */ @Override public UpdateItemResponse updateItem(UpdateItem request) { UpdateItemResponse response = (UpdateItemResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#sendItem(com.microsoft.exchange.messages.SendItem) */ @Override public SendItemResponse sendItem(SendItem request) { SendItemResponse response = (SendItemResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#moveItem(com.microsoft.exchange.messages.MoveItem) */ @Override public MoveItemResponse moveItem(MoveItem request) { MoveItemResponse response = (MoveItemResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#copyItem(com.microsoft.exchange.messages.CopyItem) */ @Override public CopyItemResponse copyItem(CopyItem request) { CopyItemResponse response = (CopyItemResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#createAttachment(com.microsoft.exchange.messages.CreateAttachment) */ @Override public CreateAttachmentResponse createAttachment(CreateAttachment request) { CreateAttachmentResponse response = (CreateAttachmentResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#deleteAttachment(com.microsoft.exchange.messages.DeleteAttachment) */ @Override public DeleteAttachmentResponse deleteAttachment(DeleteAttachment request) { DeleteAttachmentResponse response = (DeleteAttachmentResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#getAttachment(com.microsoft.exchange.messages.GetAttachment) */ @Override public GetAttachmentResponse getAttachment(GetAttachment request) { GetAttachmentResponse response = (GetAttachmentResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#getDelegate(com.microsoft.exchange.messages.GetDelegate) */ @Override public GetDelegateResponse getDelegate(GetDelegate request) { GetDelegateResponse response = (GetDelegateResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#addDelegate(com.microsoft.exchange.messages.AddDelegate) */ @Override public AddDelegateResponse addDelegate(AddDelegate request) { AddDelegateResponse response = (AddDelegateResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#removeDelegate(com.microsoft.exchange.messages.RemoveDelegate) */ @Override public RemoveDelegateResponse removeDelegate(RemoveDelegate request) { RemoveDelegateResponse response = (RemoveDelegateResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#updateDelegate(com.microsoft.exchange.messages.UpdateDelegate) */ @Override public UpdateDelegateResponse updateDelegate(UpdateDelegate request) { UpdateDelegateResponse response = (UpdateDelegateResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#getUserAvailability(com.microsoft.exchange.messages.GetUserAvailabilityRequest) */ @Override public GetUserAvailabilityResponse getUserAvailability( GetUserAvailabilityRequest request) { GetUserAvailabilityResponse response = (GetUserAvailabilityResponse) internalInvoke(request, new SoapActionCallback("http://schemas.microsoft.com/exchange/services/2006/messages/GetUserAvailability")); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#getUserOofSettings(com.microsoft.exchange.messages.GetUserOofSettingsRequest) */ @Override public GetUserOofSettingsResponse getUserOofSettings( GetUserOofSettingsRequest request) { GetUserOofSettingsResponse response = (GetUserOofSettingsResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#setUserOofSettings(com.microsoft.exchange.messages.SetUserOofSettingsRequest) */ @Override public SetUserOofSettingsResponse setUserOofSettings( SetUserOofSettingsRequest request) { SetUserOofSettingsResponse response = (SetUserOofSettingsResponse) internalInvoke(request); return response; } /* (non-Javadoc) * @see com.microsoft.exchange.ExchangeWebServices#getServerTimeZones(com.microsoft.exchange.messages.GetServerTimeZones) */ @Override public GetServerTimeZonesResponse getServerTimeZones( GetServerTimeZones request) { GetServerTimeZonesResponse response = (GetServerTimeZonesResponse) internalInvoke(request); return response; } @Override public EmptyFolderResponse emptyFolder(EmptyFolder request) { EmptyFolderResponse response = (EmptyFolderResponse) internalInvoke(request); return response; } /** * * @param request * @return */ protected Object internalInvoke(Object request) { return internalInvoke(request, null); } /** * * @param request * @return */ protected Object internalInvoke(Object request, WebServiceMessageCallback callback) { try { Object result; log.trace("ExchangeRequest="+request); if(null == callback) { result = getWebServiceTemplate().marshalSendAndReceive(request); } else { result = getWebServiceTemplate().marshalSendAndReceive(request, callback); } return result; } catch (SoapFaultClientException e) { if(e.getMessage().equals("The impersonation principal name is invalid.")) { throw new ExchangeInvalidUPNRuntimeException(e); } if(log.isTraceEnabled()) { log.error("SoapFaultClientException encountered for " + request+". "+e.getMessage()); }else { log.error("SoapFaultClientException encountered "+e.getMessage()); } throw new ExchangeWebServicesRuntimeException(e); } } }