/** * Sets the timeout for this web service client. Every port created by a JAX-WS can be cast to * BindingProvider. */ public static void setTimeout(BindingProvider port, int timeout) { if (port == null) { throw new IllegalArgumentException("port must not be null!"); } Map<String, Object> ctxt = port.getRequestContext(); ctxt.put("com.sun.xml.ws.developer.JAXWSProperties.CONNECT_TIMEOUT", timeout); ctxt.put("com.sun.xml.ws.connect.timeout", timeout); ctxt.put("com.sun.xml.ws.internal.connect.timeout", timeout); ctxt.put("com.sun.xml.ws.request.timeout", timeout); ctxt.put("com.sun.xml.internal.ws.request.timeout", timeout); // We don't want to use proprietary Sun code // ctxt.put(BindingProviderProperties.REQUEST_TIMEOUT, timeout); // ctxt.put(BindingProviderProperties.CONNECT_TIMEOUT, timeout); }
/** * Determines the reference to a web service provided by a technical * service. * * @param <T> * The type of service obtained. * @param localWsdlUrl * The URL to a local service-related WSDL. The WSDL should be * provided as file in a bundled .jar file. * @param serviceClass * The service class implemented by the WSDL. * @return The web service reference. * @throws ParserConfigurationException * @throws WebServiceException * Has to be caught by a caller, although it's a runtime * exception */ public <T> T getPort(URL localWsdlUrl, Class<T> serviceClass) throws ParserConfigurationException, WebServiceException { Service service = getService(localWsdlUrl, serviceClass); //EndpointReference epr = determineEndpointReference(); T port = service.getPort(serviceClass); BindingProvider bindingProvider = (BindingProvider) port; Map<String, Object> clientRequestContext = bindingProvider .getRequestContext(); clientRequestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, details.getEndpointURL()); if (requiresUserAuthentication(userName, password)) { // BindingProvider bindingProvider = (BindingProvider) port; // Map<String, Object> clientRequestContext = bindingProvider // .getRequestContext(); clientRequestContext.put(BindingProvider.USERNAME_PROPERTY, userName); clientRequestContext.put(BindingProvider.PASSWORD_PROPERTY, password); } return port; }
/** * IWS Access WebService Client Constructor. Takes the URL for the WSDL as * parameter, to generate a new WebService Client instance.<br /> * For example: https://iws.iaeste.net:9443/iws-ws/administrationWS?wsdl * * @param wsdlLocation IWS Administration WSDL URL * @throws MalformedURLException if not a valid URL */ public AdministrationWSClient(final String wsdlLocation) throws MalformedURLException { super(new URL(wsdlLocation), ACCESS_SERVICE_NAME); client = getPort(ACCESS_SERVICE_PORT, AdministrationWS.class); // The CXF will by default attempt to read the URL from the WSDL at the // Server, which is normally given with the server's name. However, as // we're running via a load balancer and/or proxies, this address may // not be available or resolvable via DNS. Instead, we force using the // same WSDL for requests as we use for accessing the server. // Binding: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-Howtooverridetheserviceaddress? ((BindingProvider) client).getRequestContext().put(ENDPOINT_ADDRESS, wsdlLocation); // The CXF has a number of default Policy settings, which can all be // controlled via the internal Policy Scheme. To override or update the // default values, the Policy must be exposed. Which is done by setting // a new Policy Scheme which can be access externally. // Policy: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-HowtoconfiguretheHTTPConduitfortheSOAPClient? final Client proxy = ClientProxy.getClient(client); final HTTPConduit conduit = (HTTPConduit) proxy.getConduit(); // Finally, set the Policy into the HTTP Conduit. conduit.setClient(policy); }
public <T> void setEndpointInContext(BindingProvider client, Map<String, Setting> settings, Class<T> serviceClass) { Map<String, Object> clientRequestContext = client.getRequestContext(); String wsUrl = ""; if (isSsoMode(settings)) { wsUrl = settings.get( PlatformConfigurationKey.BSS_STS_WEBSERVICE_URL.name()) .getValue(); } else { wsUrl = settings.get( PlatformConfigurationKey.BSS_WEBSERVICE_URL.name()) .getValue(); } wsUrl = wsUrl.replace("{SERVICE}", serviceClass.getSimpleName()); clientRequestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, wsUrl); }
/** * Gets the user details from BES. If user is null, the current user details * will be returned, otherwise of the specified user. * * @param si * @param user * @param password * @param controllerId * @return * @throws APPlatformException * @throws BESNotificationException */ public VOUserDetails getUserDetails(ServiceInstance si, VOUser user, String password, Optional<String> controllerId) throws APPlatformException { VOUserDetails userDetails = null; IdentityService idServ = getBESWebService(IdentityService.class, si, controllerId); if (user != null) { Map<String, Setting> proxySettings = configService .getAllProxyConfigurationSettings(); boolean isSso = isSsoMode(proxySettings); setUserCredentialsInContext((BindingProvider) idServ, isSso ? user.getUserId() : String.valueOf(user.getKey()), password, proxySettings); } try { userDetails = idServ.getCurrentUserDetails(); } catch (Exception e) { throw new APPlatformException(e.getMessage(), e); } return userDetails; }
@Test public void setUserCredentialsInContext_INTERNAL() { // given Map<String, Setting> settings = getSettingsForMode("INTERNAL"); BindingProvider client = Mockito.mock(BindingProvider.class); Map<String, String> context = new HashMap<>(); Mockito.doReturn(context).when(client).getRequestContext(); // when besDAO.setUserCredentialsInContext(client, USER, PASSWORD, settings); // then assertNull(client.getRequestContext().get( "username")); assertNull(client.getRequestContext().get( "password")); assertEquals( USER, client.getRequestContext().get( BindingProvider.USERNAME_PROPERTY)); assertEquals( PASSWORD, client.getRequestContext().get( BindingProvider.PASSWORD_PROPERTY)); }
@Test public void setUserCredentialsInContext_SAML_SP() { // given Map<String, Setting> settings = getSettingsForMode("SAML_SP"); BindingProvider client = Mockito.mock(BindingProvider.class); Map<String, String> context = new HashMap<>(); Mockito.doReturn(context).when(client).getRequestContext(); // when besDAO.setUserCredentialsInContext(client, USER, PASSWORD, settings); // then assertNull(client.getRequestContext().get( BindingProvider.USERNAME_PROPERTY)); assertNull(client.getRequestContext().get( BindingProvider.PASSWORD_PROPERTY)); assertEquals(USER, client.getRequestContext().get("username")); assertEquals(PASSWORD, client.getRequestContext().get("password")); }
@Test public void getUserDetails_givenUser_INTERNAL() throws APPlatformException { // given besDAO.configService = confServ; Map<String, Setting> settings = getSettingsForMode("INTERNAL"); doReturn(settings).when(besDAO.configService) .getAllProxyConfigurationSettings(); doReturn(idServ).when(besDAO).getBESWebService( eq(IdentityService.class), any(ServiceInstance.class), any(Optional.class)); VOUser user = givenUser(null, "mail"); // when besDAO.getUserDetails(new ServiceInstance(), user, "password", Optional.empty()); // then verify(besDAO).setUserCredentialsInContext(any(BindingProvider.class), eq(Long.valueOf(user.getKey()).toString()), eq("password"), eq(settings)); verify(idServ).getCurrentUserDetails(); }
@Test public void getUserDetails_givenUser_SSO() throws APPlatformException { // given besDAO.configService = confServ; Map<String, Setting> settings = getSettingsForMode("SAML_SP"); doReturn(settings).when(besDAO.configService) .getAllProxyConfigurationSettings(); doReturn(idServ).when(besDAO).getBESWebService( eq(IdentityService.class), any(ServiceInstance.class), any(Optional.class)); VOUser user = givenUser(null, "mail"); // when besDAO.getUserDetails(new ServiceInstance(), user, "password", Optional.empty()); // then verify(besDAO).setUserCredentialsInContext(any(BindingProvider.class), eq(user.getUserId()), eq("password"), eq(settings)); verify(idServ).getCurrentUserDetails(); }
@Test public void getClientForBESTechnologyManager_INTERNAL_userInConfig() throws MalformedURLException, APPlatformException { // given Map<String, Setting> proxySettings = getSettingsForMode("INTERNAL"); Map<String, Setting> controllerSettings = getControllerSettings(true, true, true); BesDAO besDAO = mockWebServiceSetup(proxySettings, controllerSettings); // when IdentityService client = besDAO.getBESWebService(IdentityService.class, new ServiceInstance(), Optional.empty()); // then verify(besDAO, times(1)).setUserCredentialsInContext( (BindingProvider) client, USER_KEY_TM, USER_PWD_TM, proxySettings); }
@Test public void getClientForBESTechnologyManager_INTERNAL_userKeyNotInConfig_userInTS() throws MalformedURLException, BadResultException, APPlatformException { // given Map<String, Setting> proxySettings = getSettingsForMode("INTERNAL"); Map<String, Setting> controllerSettings = getControllerSettings(true, false, true); BesDAO besDAO = mockWebServiceSetup(proxySettings, controllerSettings); ServiceInstance si = getServiceInstanceWithParameters(true, true); // when IdentityService client = besDAO.getBESWebService(IdentityService.class, si, Optional.empty()); // then verify(besDAO, times(1)).setUserCredentialsInContext( (BindingProvider) client, USER_TM_TechSvc, USER_PWD_TM_TechSvc, proxySettings); }
@Test public void getClientForBESTechnologyManager_INTERNAL_userPwdNotInConfig_userInTS() throws MalformedURLException, BadResultException, APPlatformException { // given Map<String, Setting> proxySettings = getSettingsForMode("INTERNAL"); Map<String, Setting> controllerSettings = getControllerSettings(true, true, false); BesDAO besDAO = mockWebServiceSetup(proxySettings, controllerSettings); ServiceInstance si = getServiceInstanceWithParameters(true, true); // when IdentityService client = besDAO.getBESWebService(IdentityService.class, si, Optional.empty()); // then verify(besDAO, times(1)).setUserCredentialsInContext( (BindingProvider) client, USER_TM_TechSvc, USER_PWD_TM_TechSvc, proxySettings); }
@Test public void getClientForBESTechnologyManager_SSO_userInConfig() throws MalformedURLException, APPlatformException { // given Map<String, Setting> proxySettings = getSettingsForMode("SAML_SP"); Map<String, Setting> controllerSettings = getControllerSettings(true, true, true); BesDAO besDAO = mockWebServiceSetup(proxySettings, controllerSettings); // when IdentityService client = besDAO.getBESWebService(IdentityService.class, new ServiceInstance(), Optional.empty()); // then verify(besDAO, times(1)).setUserCredentialsInContext( (BindingProvider) client, USER_ID_TM, USER_PWD_TM, proxySettings); }
@Test public void getClientForBESTechnologyManager_SSO_userIdNotInConfig_userInTS() throws MalformedURLException, BadResultException, APPlatformException { // given Map<String, Setting> proxySettings = getSettingsForMode("SAML_SP"); Map<String, Setting> controllerSettings = getControllerSettings(false, true, true); BesDAO besDAO = mockWebServiceSetup(proxySettings, controllerSettings); ServiceInstance si = getServiceInstanceWithParameters(true, true); // when IdentityService client = besDAO.getBESWebService(IdentityService.class, si, Optional.empty()); // then verify(besDAO, times(1)).setUserCredentialsInContext( (BindingProvider) client, USER_TM_TechSvc, USER_PWD_TM_TechSvc, proxySettings); }
@Test public void getClientForBESTechnologyManager_SSO_userPwdNotInConfig_userInTS() throws MalformedURLException, BadResultException, APPlatformException { // given Map<String, Setting> proxySettings = getSettingsForMode("SAML_SP"); Map<String, Setting> controllerSettings = getControllerSettings(true, true, false); BesDAO besDAO = mockWebServiceSetup(proxySettings, controllerSettings); ServiceInstance si = getServiceInstanceWithParameters(true, true); // when IdentityService client = besDAO.getBESWebService(IdentityService.class, si, Optional.of("")); // then verify(besDAO, times(1)).setUserCredentialsInContext( (BindingProvider) client, USER_TM_TechSvc, USER_PWD_TM_TechSvc, proxySettings); }
public <T> T getPort(Service service, Class<T> serviceClass) throws ParserConfigurationException { // and determine the real endpoint belonging to the provisioning // URL, and create the port based on it. Doing so, we omit // parsing the remote WSDL twice and also related authentication // problems EndpointReference epr = determineEndpointReference(); T port = service.getPort(epr, serviceClass); if (requiresUserAuthentication(userName, password)) { BindingProvider bindingProvider = (BindingProvider) port; Map<String, Object> clientRequestContext = bindingProvider .getRequestContext(); clientRequestContext.put(BindingProvider.USERNAME_PROPERTY, userName); clientRequestContext.put(BindingProvider.PASSWORD_PROPERTY, password); } return port; }
private void fillSOAPAction(Packet packet, boolean isAddressingEnabled) { final boolean p = packet.packetTakesPriorityOverRequestContext; final String localSoapAction = p ? packet.soapAction : soapAction; final Boolean localSoapActionUse = p ? (Boolean) packet.invocationProperties.get(BindingProvider.SOAPACTION_USE_PROPERTY) : soapActionUse; //JAX-WS-596: Check the semantics of SOAPACTION_USE_PROPERTY before using the SOAPACTION_URI_PROPERTY for // SoapAction as specified in the javadoc of BindingProvider. The spec seems to be little contradicting with // javadoc and says that the use property effects the sending of SOAPAction property. // Since the user has the capability to set the value as "" if needed, implement the javadoc behavior. if ((localSoapActionUse != null && localSoapActionUse) || (localSoapActionUse == null && isAddressingEnabled)) { if (localSoapAction != null) { packet.soapAction = localSoapAction; } } if ((!isAddressingEnabled && (localSoapActionUse == null || !localSoapActionUse)) && localSoapAction != null) { LOGGER.warning("BindingProvider.SOAPACTION_URI_PROPERTY is set in the RequestContext but is ineffective," + " Either set BindingProvider.SOAPACTION_USE_PROPERTY to true or enable AddressingFeature"); } }
@Test public void testOutHeaderCXFClientNoRelay() throws Exception { Thread.sleep(5000); HeaderService s = new HeaderService(getClass().getClassLoader().getResource("soap_header.wsdl"), HeaderService.SERVICE); HeaderTester proxy = s.getSoapPortNoRelay(); ((BindingProvider)proxy).getRequestContext() .put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:" + portE3 + "/CxfMessageHeadersRelayTest/HeaderService/"); OutHeader me = new OutHeader(); me.setRequestType("CXF user"); Holder<OutHeaderResponse> result = new Holder<OutHeaderResponse>(new OutHeaderResponse()); Holder<SOAPHeaderData> header = new Holder<SOAPHeaderData>(new SOAPHeaderData()); try { proxy.outHeader(me, result, header); } catch (Exception e) { // do nothing } assertTrue("Ultimate remote HeaderTester.outHeader() destination was not reached", result.value.getResponseType().equals("pass")); assertTrue("Expected in band response header *not* to propagate but it did", header.value == null); }
@Test public void testJaxWsBeanFromCxfRoute() throws Exception { URL wsdlURL = getClass().getClassLoader().getResource("person.wsdl"); PersonService ss = new PersonService(wsdlURL, new QName("http://camel.apache.org/wsdl-first", "PersonService")); Person client = ss.getSoap(); ((BindingProvider)client).getRequestContext() .put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:" + CXFTestSupport.getPort1() + "/CxfBeanTest/PersonService/"); Holder<String> personId = new Holder<String>(); personId.value = "hello"; Holder<String> ssn = new Holder<String>(); Holder<String> name = new Holder<String>(); client.getPerson(personId, ssn, name); assertEquals("Get a wrong personId", "hello", personId.value); assertEquals("Get a wrong SSN", "000-000-0000", ssn.value); assertEquals("Get a wrong name", "Bonjour", name.value); }
@Test public void testInvokingServiceFromCXFClient() throws Exception { URL wsdlURL = getClass().getClassLoader().getResource("person-non-wrapper.wsdl"); PersonService ss = new PersonService(wsdlURL, new QName("http://camel.apache.org/non-wrapper", "PersonService")); Person client = ss.getSoap(); ((BindingProvider)client).getRequestContext() .put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:" + port1 + "/CxfNonWrapperTest/PersonService/"); GetPerson request = new GetPerson(); request.setPersonId("hello"); GetPersonResponse response = client.getPerson(request); assertEquals("we should get the right answer from router", "Bonjour", response.getName()); request.setPersonId(""); try { client.getPerson(request); fail("We expect to get the UnknowPersonFault here"); } catch (UnknownPersonFault fault) { // We expect to get fault here } }
@Test public void testInHeaderCXFClientNoRelay() throws Exception { HeaderService s = new HeaderService(getClass().getClassLoader().getResource("soap_header.wsdl"), HeaderService.SERVICE); HeaderTester proxy = s.getSoapPortNoRelay(); ((BindingProvider)proxy).getRequestContext() .put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:" + portE3 + "/CxfMessageHeadersRelayTest/HeaderService/"); InHeader me = new InHeader(); me.setRequestType("CXF user"); InHeaderResponse response = null; try { response = proxy.inHeader(me, Constants.IN_HEADER_DATA); } catch (Exception e) { // do nothing } assertTrue("Expected in in band header *not* to propagate but it did", response.getResponseType().equals("pass")); }
private void updateBindingProvider(BindingProvider bindingProvider, String uri) { Map<String, Object> requestContext = bindingProvider.getRequestContext(); requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, uri); requestContext.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true); updateRequestTimeout(); if (this.ignoreSslErrors) { IgnoreSslErrors.ignoreErrors(bindingProvider); } if (this.trustManager != null) { IgnoreSslErrors.useTrustManager(bindingProvider, this.trustManager); } }
/** * Alternative constructor for test classes * * @param serverUrl * @param userName * @param password * @throws ServiceException * @throws MalformedURLException */ public Connection(String serverUrl, String userName, String password) throws ServiceException, MalformedURLException { this.username = userName; this.password = password; Service service = Service.create(new URL(serverUrl), new QName( "http://api2.scrumworks.danube.com/", "ScrumWorksAPIBeanService")); endpoint = service.getPort(ScrumWorksAPIService.class); ((BindingProvider) endpoint).getRequestContext().put( BindingProvider.USERNAME_PROPERTY, username); ((BindingProvider) endpoint).getRequestContext().put( BindingProvider.PASSWORD_PROPERTY, password); }
@Test public void testInvokingService() throws Exception { if (MtomTestHelper.isAwtHeadless(null, log)) { return; } Holder<byte[]> photo = new Holder<byte[]>("RequestFromCXF".getBytes("UTF-8")); Holder<Image> image = new Holder<Image>(getImage("/java.jpg")); Hello port = getPort(); SOAPBinding binding = (SOAPBinding) ((BindingProvider)port).getBinding(); binding.setMTOMEnabled(true); port.detail(photo, image); assertEquals("ResponseFromCamel", new String(photo.value, "UTF-8")); assertNotNull(image.value); }
/** * IWS Access WebService Client Constructor. Takes the URL for the WSDL as * parameter, to generate a new WebService Client instance.<br /> * For example: https://iws.iaeste.net:9443/iws-ws/accessWS?wsdl * * @param wsdlLocation IWS Access WSDL URL * @throws MalformedURLException if not a valid URL */ public AccessWSClient(final String wsdlLocation) throws MalformedURLException { super(new URL(wsdlLocation), ACCESS_SERVICE_NAME); client = getPort(ACCESS_SERVICE_PORT, AccessWS.class); // The CXF will by default attempt to read the URL from the WSDL at the // Server, which is normally given with the server's name. However, as // we're running via a load balancer and/or proxies, this address may // not be available or resolvable via DNS. Instead, we force using the // same WSDL for requests as we use for accessing the server. // Binding: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-Howtooverridetheserviceaddress? ((BindingProvider) client).getRequestContext().put(ENDPOINT_ADDRESS, wsdlLocation); // The CXF has a number of default Policy settings, which can all be // controlled via the internal Policy Scheme. To override or update the // default values, the Policy must be exposed. Which is done by setting // a new Policy Scheme which can be access externally. // Policy: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-HowtoconfiguretheHTTPConduitfortheSOAPClient? final Client proxy = ClientProxy.getClient(client); final HTTPConduit conduit = (HTTPConduit) proxy.getConduit(); // Finally, set the Policy into the HTTP Conduit. conduit.setClient(policy); }
/** * IWS Access WebService Client Constructor. Takes the URL for the WSDL as * parameter, to generate a new WebService Client instance.<br /> * For example: https://iws.iaeste.net:9443/iws-ws/committeeWS?wsdl * * @param wsdlLocation IWS Committees WSDL URL * @throws MalformedURLException if not a valid URL */ public CommitteeWSClient(final String wsdlLocation) throws MalformedURLException { super(new URL(wsdlLocation), ACCESS_SERVICE_NAME); client = getPort(ACCESS_SERVICE_PORT, CommitteeWS.class); // The CXF will by default attempt to read the URL from the WSDL at the // Server, which is normally given with the server's name. However, as // we're running via a load balancer and/or proxies, this address may // not be available or resolvable via DNS. Instead, we force using the // same WSDL for requests as we use for accessing the server. // Binding: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-Howtooverridetheserviceaddress? ((BindingProvider) client).getRequestContext().put(ENDPOINT_ADDRESS, wsdlLocation); // The CXF has a number of default Policy settings, which can all be // controlled via the internal Policy Scheme. To override or update the // default values, the Policy must be exposed. Which is done by setting // a new Policy Scheme which can be access externally. // Policy: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-HowtoconfiguretheHTTPConduitfortheSOAPClient? final Client proxy = ClientProxy.getClient(client); final HTTPConduit conduit = (HTTPConduit) proxy.getConduit(); // Finally, set the Policy into the HTTP Conduit. conduit.setClient(policy); }
/** * IWS Access WebService Client Constructor. Takes the URL for the WSDL as * parameter, to generate a new WebService Client instance.<br /> * For example: https://iws.iaeste.net:9443/iws-ws/studentWS?wsdl * * @param wsdlLocation IWS Students WSDL URL * @throws MalformedURLException if not a valid URL */ public StudentWSClient(final String wsdlLocation) throws MalformedURLException { super(new URL(wsdlLocation), ACCESS_SERVICE_NAME); client = getPort(ACCESS_SERVICE_PORT, StudentWS.class); // The CXF will by default attempt to read the URL from the WSDL at the // Server, which is normally given with the server's name. However, as // we're running via a load balancer and/or proxies, this address may // not be available or resolvable via DNS. Instead, we force using the // same WSDL for requests as we use for accessing the server. // Binding: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-Howtooverridetheserviceaddress? ((BindingProvider) client).getRequestContext().put(ENDPOINT_ADDRESS, wsdlLocation); // The CXF has a number of default Policy settings, which can all be // controlled via the internal Policy Scheme. To override or update the // default values, the Policy must be exposed. Which is done by setting // a new Policy Scheme which can be access externally. // Policy: http://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport%28includingSSLsupport%29-HowtoconfiguretheHTTPConduitfortheSOAPClient? final Client proxy = ClientProxy.getClient(client); final HTTPConduit conduit = (HTTPConduit) proxy.getConduit(); // Finally, set the Policy into the HTTP Conduit. conduit.setClient(policy); }