diff --git a/src/main/java/com/eactive/eai/custom/adapter/app/impl/JwtTokenCreator.java b/src/main/java/com/eactive/eai/custom/adapter/app/impl/JwtTokenCreator.java new file mode 100644 index 0000000..47a4ded --- /dev/null +++ b/src/main/java/com/eactive/eai/custom/adapter/app/impl/JwtTokenCreator.java @@ -0,0 +1,477 @@ +package com.eactive.eai.custom.adapter.app.impl; + +import java.text.ParseException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +//import org.codehaus.jackson.map.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.common.util.OAuth2Utils; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.OAuth2Request; +import org.springframework.security.oauth2.provider.TokenRequest; +import org.springframework.security.oauth2.provider.token.DefaultTokenServices; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; +import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; + +import com.eactive.eai.adapter.app.BusinessApplication; +import com.eactive.eai.adapter.http.dynamic.filter.ApiAuthFilter; +import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException; +//import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthFilter; +import com.eactive.eai.authserver.service.OAuth2Manager; +import com.eactive.eai.authserver.util.BeanUtils; +import com.eactive.eai.authserver.vo.ClientVO; +import com.eactive.eai.common.util.Logger; +//import com.nimbusds.jwt.SignedJWT; + +/** + * JWT 토큰을 발급한다.(인증은 요청시스템에서 수행하고 토큰만 발급) + * + * @author + * + */ +public class JwtTokenCreator implements BusinessApplication { + public static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT); + + private static final boolean VERYFY_CLIENT_SECRET = true; + private static final String[] GRANT_TYPES = { "client_credentials", "authorization_code", "password", + "refresh_token" }; + + @SuppressWarnings("unchecked") + @Override + public Object executeApplication(Properties prop, Object messageBytes, Properties tempProp) throws Exception { + // 응답전문용 Json Object + JSONObject resObject = new JSONObject(); + + try { + if (messageBytes == null) { + throw new Exception("Message is null."); + } + + String message = new String((byte[]) messageBytes); + if (StringUtils.isBlank(message)) { + throw new Exception("Message is empty."); + } + + /** + * { + * "grant_type":"client_credentials", + * "client_id":"WNHZOadBfB9UCPPuq6YArKUW87elXmZX", + * "client_secret":"JhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9", + * "scope":"manage", + * "expires_in":3600, + * "resource_ids":"aaa, bbb", + * "authorities":"ROLE_ADM, ROLE_DEV", + * "user_name":"aaaaaaaaaaaaaa", + * "support_refresh_token_yn": "Y", + * "refresh_token_expires_in":86400, + * "refresh_token":"JhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOj~~", + * "iss":"AZABBB0000", + * "aud":"ZZAAAA0000" + * } + */ + boolean isVerifyClientSecret = VERYFY_CLIENT_SECRET; + // 요청전문 Json Object + JSONObject jsonObject = (JSONObject) JSONValue.parse(message); + + /* 2022.5.25. yseo + * 복합거래여부 확인, 복합거래의 경우 요청전문의 내용을 응답전문에 그대로 복사 + * 복합거래 : 토큰발급 이후 2차 처리를 위한 Outbound Adapter를 다시 호출하는 거래 + * 복합거래 대상 EAIServiceCD는 APP Adapter의 프로퍼티(SVC_CD)에 등록해서 관리. + */ + String svcCds = prop.getProperty("SVC_CD"); + String[] svcCdArr = org.springframework.util.StringUtils.tokenizeToStringArray(svcCds, ","); + Boolean isComplex = ArrayUtils.contains(svcCdArr, tempProp.getProperty("EAISvcCd"))?true:false; + if(isComplex) { + resObject = jsonObject; + } + logger.debug("1. isComplex : [" + isComplex + "]"); + + String grantType = (String) jsonObject.get(OAuth2Utils.GRANT_TYPE); + if (!ArrayUtils.contains(GRANT_TYPES, grantType)) { + throw new JwtAuthException("unsupported_grant_type", "Unsupported grant type"); + } + logger.debug("2. grantType : [" + grantType + "]"); + + String clientId = (String) jsonObject.get(OAuth2Utils.CLIENT_ID); + if (StringUtils.isBlank(clientId)) { + throw new JwtAuthException("invalid_client", "Bad client credentials(client_id is empty)"); + /* clientId에 허용된 grantType인지 확인 2022.05.23 yseo*/ + } else { + veryfyGrantType(clientId, grantType); + } + logger.debug("3. clientId : [" + clientId + "]"); + + /* grantType = "client_credentials" 이면 client_secret 체크 2022.05.23 yseo + * Mydata 관련해서는 무조건 체크해야함. + */ +// if (!StringUtils.equalsIgnoreCase(grantType, "client_credentials")) isVerifyClientSecret = false; + if (isVerifyClientSecret) { + String clientSecret = (String) jsonObject.get("client_secret"); + if (StringUtils.isBlank(clientSecret)) { + throw new JwtAuthException("invalid_client", "Bad client credentials(client_secret is empty)"); + } + veryfyClientSecret(clientId, clientSecret); + logger.debug("4. clientSecret : [" + clientSecret + "]"); + } + + Set scopeSet = assignScope((String) jsonObject.get(OAuth2Utils.SCOPE)); + if (scopeSet == null || scopeSet.size() == 0) { + if (!StringUtils.equals(grantType, "refresh_token")) { + throw new Exception("scope is empty."); + } + } + logger.debug("5. scopeSet : [" + scopeSet + "]"); + + Set resourceIdSet = assignResourceIds((String) jsonObject.get("resource")); + Set authoritiesSet = assignAuthorities((String) jsonObject.get("authorities")); + + String userName = (String) jsonObject.get("user_name"); + if (StringUtils.equals(grantType, "password") || StringUtils.equals(grantType, "authorization_code")) { + if (StringUtils.isBlank(userName)) { + throw new Exception("user_name is empty."); + } + } + logger.debug("6. userName : [" + userName + "]"); + + /* 요청정보에 expires_in(토큰유효기간) 값이 없는 경우, client정보에 등록된 유효기간 찾아 대체 2022.05.23 yseo*/ + String expIn = String.valueOf(jsonObject.get(OAuth2AccessToken.EXPIRES_IN)); + Long expiresIn = null; + if (StringUtils.isNumeric(expIn)) { + expiresIn = Long.parseLong(expIn); + } else if (StringUtils.isBlank(expIn) || StringUtils.equalsIgnoreCase("null", expIn)) { + expiresIn = assignDefaultExpiresIn(clientId, "expires_in"); + } else { + throw new Exception("expires_in is not numeric."); + } + logger.debug("7. expiresIn : [" + expIn + "]"); +// Long expiresIn = (Long) jsonObject.get(OAuth2AccessToken.EXPIRES_IN); +// if (expiresIn == null) { +// expiresIn = assignDefaultExpiresIn(clientId, "expires_in"); +// } + + boolean supportRefreshToken = BooleanUtils.toBoolean((String) jsonObject.getOrDefault("support_refresh_token_yn", "N")); + /* 요청정보에 refresh_token_expires_in(리프레시토큰유효기간) 값이 없는 경우, client정보에 등록된 유효기간 찾아 대체 2022.05.23 yseo*/ + String refreshExpIn = String.valueOf(jsonObject.get("refresh_token_expires_in")); + Long refreshTokenExpiresIn = null; + if (supportRefreshToken && StringUtils.isNumeric(refreshExpIn)) { + refreshTokenExpiresIn = Long.parseLong(refreshExpIn); + } else if (supportRefreshToken && (StringUtils.isBlank(refreshExpIn) || StringUtils.equalsIgnoreCase("null", refreshExpIn))) { + refreshTokenExpiresIn = assignDefaultExpiresIn(clientId, "refresh_token_expires_in"); + } else if (supportRefreshToken) { + throw new Exception("refresh_token_expires_in is not numeric."); + } + logger.debug("8. refreshTokenExpiresIn : [" + refreshExpIn + "]"); +// Long refreshTokenExpiresIn = (Long) jsonObject.get("refresh_token_expires_in"); +// if (supportRefreshToken && refreshTokenExpiresIn == null) { +// refreshTokenExpiresIn = assignDefaultExpiresIn(clientId, "refresh_token_expires_in"); +// } + + String refreshToken = (String) jsonObject.get("refresh_token"); + if (StringUtils.equals(grantType, "refresh_token") && StringUtils.isBlank(refreshToken)) { + throw new JwtAuthException("invalid_token", "refresh_token is empty."); + } + logger.debug("9. refreshToken : [" + refreshToken + "]"); + + String iss = (String) jsonObject.get("iss"); +// if (StringUtils.isBlank(iss)) { +// iss = assignDefaultStringValue(clientId, "iss"); +// } +// logger.debug("10. iss : [" + iss + "]"); +// + String aud = (String) jsonObject.get("aud"); +// if (StringUtils.isBlank(aud)) { +// aud = assignDefaultStringValue(clientId, "aud"); +// } +// logger.debug("11. aud : [" + aud + "]"); + + String tokenStr = createToken(grantType, clientId, scopeSet, resourceIdSet, authoritiesSet, userName, expiresIn, + supportRefreshToken, refreshTokenExpiresIn, refreshToken, iss, aud); +// logger.debug("#####created tokenStr==>"+tokenStr); + + //20211122 bearer -> Bearer로 변환철. mydata api준수 + JSONObject jsonObj = (JSONObject) JSONValue.parse(tokenStr); + String tokenType = (String)jsonObj.get("token_type"); + if(StringUtils.isNotBlank(tokenType) && StringUtils.equalsIgnoreCase(tokenType, "bearer")) { + jsonObj.put("token_type","Bearer"); + } + jsonObj.remove("jti"); + jsonObj.put("resource", (String) jsonObject.get("resource")); + if (StringUtils.equals(grantType, "password") || StringUtils.equals(grantType, "authorization_code")) { + jsonObj.put("refresh_token_expires_in", refreshTokenExpiresIn-1); + } + tokenStr = jsonObj.toJSONString(); + logger.debug("##### Bearer checked tokenStr==>"+tokenStr); + + // 복합거래의 경우 발급된 토큰정보를 "TOKEN_DATAGROUP" 그룹으로 추가 + if(isComplex) { + resObject.put("TOKEN_DATAGROUP", jsonObj); + } else { + resObject.putAll(jsonObj); + } + String resStr = resObject.toJSONString(); + + return resStr.getBytes(); + } catch (JwtAuthException e) { + logger.error(e); + + JSONObject errorJson = new JSONObject(); + errorJson.put("error", e.getCode()); + errorJson.put("error_description", e.getMessage()); + resObject.putAll(errorJson); + return resObject.toJSONString().getBytes(); + } catch (Exception e) { + logger.error(e); + + JSONObject errorJson = new JSONObject(); + errorJson.put("error", "invalid_request"); + errorJson.put("error_description", e.getMessage()); + resObject.putAll(errorJson); + return resObject.toJSONString().getBytes(); + } + } + + private Set assignResourceIds(String resourceIds) throws Exception { + if (StringUtils.isBlank(resourceIds)) { + return null; + } + + String[] arr = org.springframework.util.StringUtils.tokenizeToStringArray(resourceIds, ","); + Set resourceIdSet = new HashSet(); + for (String resourceId : arr) { + resourceIdSet.add(resourceId); + } + + return resourceIdSet; + } + + private void veryfyGrantType(String clientId, String grantType) throws JwtAuthException { + ClientDetails details = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId); + if (details == null) { + throw new JwtAuthException("invalid_client", "Bad client credentials(not found)"); + } + + if (!details.getAuthorizedGrantTypes().contains(grantType)) { + throw new JwtAuthException("unsupported_grant_type", "Unsupported grant type for ClientID"); + } + } + + private void veryfyClientSecret(String clientId, String clientSecret) throws JwtAuthException { + ClientDetails details = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId); + if (details == null) { + throw new JwtAuthException("invalid_client", "Bad client credentials(not found)"); + } + + if (!StringUtils.equals(details.getClientSecret(), clientSecret)) { + throw new JwtAuthException("invalid_client", "Bad client credentials"); + } + } + + private Long assignDefaultExpiresIn(String clientId, String flag) throws JwtAuthException { + ClientDetails details = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId); + Long retLong = null; + if (details == null) { + throw new JwtAuthException("invalid_client", "Bad client credentials(not found)"); + } + + if (StringUtils.equals(flag, "expires_in") && StringUtils.isNotBlank(details.getAccessTokenValiditySeconds().toString())) { + retLong = new Long(details.getAccessTokenValiditySeconds()); + } else if (StringUtils.equals(flag, "refresh_token_expires_in") && StringUtils.isNotBlank(details.getRefreshTokenValiditySeconds().toString())) { + retLong = new Long(details.getRefreshTokenValiditySeconds()); + } else { + throw new JwtAuthException("invalid_client", "Bad expires_in/refresh_token_expires_in(not found)"); + } + return retLong; + } + + private String assignDefaultStringValue(String clientId, String flag) throws Exception { + ClientVO client = (ClientVO) OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId); + String retStr = ""; + if (client == null) { + throw new JwtAuthException("invalid_client", "Bad client credentials(not found)"); + } + + if (StringUtils.equals(flag, "iss") && StringUtils.isNotBlank(client.getIssuer())) { + retStr = client.getIssuer(); + } else if (StringUtils.equals(flag, "aud") && StringUtils.isNotBlank(client.getAudience())) { + retStr = client.getAudience(); + } else { + throw new Exception("iss/aud is null."); + } + logger.info("===================>"+flag+" : ["+retStr+"]"); + return retStr; + } + + private Set assignScope(String scopes) throws Exception { + if (StringUtils.isBlank(scopes)) { + return new HashSet(); + } + + String[] arr = org.springframework.util.StringUtils.tokenizeToStringArray(scopes, " "); + Set scopeSet = new HashSet(); + for (String scope : arr) { + scopeSet.add(scope); + } + + return scopeSet; + } + + private Set assignAuthorities(String authorities) throws Exception { + if (StringUtils.isBlank(authorities)) { + return new HashSet(); + } + + String[] arr = org.springframework.util.StringUtils.tokenizeToStringArray(authorities, ","); + Set authoritiesSet = new HashSet(); + for (String authority : arr) { + authoritiesSet.add(new SimpleGrantedAuthority(authority)); + } + + return authoritiesSet; + } + + private String createToken(String grantType, String clientId, Set scopeSet, Set resourceIdSet, + Set authoritiesSet, String userName, Long expiresIn, boolean supportRefreshToken, + Long refreshTokenExpiresIn, String refreshToken, String issuer, String audience) throws Exception { + HashMap authorizationParameters = new HashMap(); + authorizationParameters.put(OAuth2Utils.GRANT_TYPE, grantType); + authorizationParameters.put(OAuth2Utils.CLIENT_ID, clientId); +// authorizationParameters.put("iss", issuer); +// authorizationParameters.put("aud", audience); + if (StringUtils.equals(grantType, "password") || StringUtils.equals(grantType, "authorization_code")) { + authorizationParameters.put("user_name", userName); + } + + Set responseType = new HashSet(); + responseType.add(grantType); + + OAuth2Request authorizationRequest = new OAuth2Request(authorizationParameters, clientId, authoritiesSet, true, + scopeSet, resourceIdSet, "", responseType, null); + + Authentication authentication = null; + if (StringUtils.equals(grantType, "password") || StringUtils.equals(grantType, "authorization_code")) { + User userPrincipal = new User(userName, "", true, true, true, true, authoritiesSet); + authentication = new UsernamePasswordAuthenticationToken(userPrincipal, null, authoritiesSet); + } + + OAuth2Authentication authenticationRequest = new OAuth2Authentication(authorizationRequest, authentication); + authenticationRequest.setAuthenticated(true); + + DefaultTokenServices tokenServices = createDefaultTokenServices(supportRefreshToken, expiresIn, + refreshTokenExpiresIn); + OAuth2AccessToken accessToken = null; + if (StringUtils.equals(grantType, "refresh_token")) { + tokenServices.setReuseRefreshToken(true); + TokenRequest tokenRequest = new TokenRequest(authorizationParameters, clientId, scopeSet, grantType); + accessToken = tokenServices.refreshAccessToken(refreshToken, tokenRequest); + } else { + accessToken = tokenServices.createAccessToken(authenticationRequest); + } + + logger.debug("accessToken=" + accessToken.toString()); + + return new ObjectMapper().writeValueAsString(accessToken); + } + + private DefaultTokenServices createDefaultTokenServices(boolean supportRefreshToken, Long expiresIn, + Long refreshTokenExpiresIn) throws Exception { + TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); + tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter())); + + DefaultTokenServices tokenServices = new DefaultTokenServices(); + tokenServices.setTokenStore(tokenStore()); + tokenServices.setSupportRefreshToken(supportRefreshToken); + tokenServices.setTokenEnhancer(tokenEnhancerChain); + if (expiresIn != null) { + tokenServices.setAccessTokenValiditySeconds(expiresIn.intValue()); + } + if (supportRefreshToken && refreshTokenExpiresIn != null) { + tokenServices.setRefreshTokenValiditySeconds(refreshTokenExpiresIn.intValue()); + } + return tokenServices; + } + + private TokenEnhancer tokenEnhancer() { +// return BeanUtils.getBean("tokenEnhancer", TokenEnhancer.class); + return (TokenEnhancer) accessTokenConverter(); + } + + private JwtAccessTokenConverter accessTokenConverter() { + return BeanUtils.getBean("jwtAccessTokenConverter", JwtAccessTokenConverter.class); + } + + private TokenStore tokenStore() { + return new JwtTokenStore((JwtAccessTokenConverter) accessTokenConverter()); + } + + public static void main(String args[]){ + + + +// String token = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImRlZmF1bHRfc3NsX2tleSJ9.ew0KICAiaXNzIjogIkExQUFFUjAwMDAiLA0KICAiYXVkIjoiWlZBQUVNMDAwMCIsDQogICJqdGkiOiJlYmI4NmUyMi03YzZmLTQzZDItOTZiMy05NjU0MTAyZTE1M2MiLA0KICAiZXhwIjoiMTYzNjk2ODcwOSIsDQogICJzY29wZSI6ImJhbmsubGlzdCINCn0.nF0JeCHJHn7yBzhjEnge_Eqi0aAeD_WTt0iUB2V2VPJV9zWgMW-Npr3fCXlmYP5HoTjeQES5ftrxWLlLMaxRPHDKWwafgwLm3eQt9r_x_j0PRn-KpoZ9xTWy3oKCQvP0DN0IQepLZfM214nCrjdSPCV17oUS03cBW0lIDmXeROSR2auAMZvkSQqF74E_QLEKF3XLk0MM3Jz4nZp1bBj3PfJyCxjy2ibp12TN0vHccGmSItqANsbeVn0sQybdIraNzb9bptLwWe8WYyn3XugEA9-bavPOSPwrGgLENBnHnzWj1L8yS0rXuEjydCwf6HMAbpNVHQpicM0Q3xdl5W1PBA"; +// String[] components = token.split("\\s"); + + //String r "refresh_token_expires_in":"604800","refresh_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImRlZmF1bHRfc3NsX2tleSJ9.ew0KICAiaXNzIjogIkExQUFFUjAwMDAiLA0KICAiYXVkIjoiWlZBQUVNMDAwMCIsDQogICJqdGkiOiIwMzI5Y2M3Zi04Y2U2LTQxNzQtYTc5Ny1mMWRjNjg1ZmM5NDAiLA0KICAiZXhwIjoiMTYzNjk2ODcwOSINCn0.dQx6kWm1JCEgueZjUsQJYNDBu2i4P1-jVLKgUH6aX2aBFunlUBtk_zMMFIJb3OvQpz8qPc9xhs1MkM2YHdpJlNleHY3GhhjiQMfYeiCU9yOzv-zuyvOY1pCO0McmHJNdFcxoQfHHFNm4yFay3dOAFE0Z3FQ74nwxrgnzKSucrHCKyGz0pHdLWnWxHNrJMZ4NmaSyPRxU3qxdWFe1soxqgTqpW_SQkTl3D5SWXgevc6zihPPpFhCSOJ39RrJlIVSH1IY5NRAm71AoaZ6ooLsLvPNED3Z7rG-g9coKEU_DASeCNslRZrP0D3azqswFeu-np3zFZUTrgP_TNT6FFReEnA"; + try { + JwtTokenCreator jtc = new JwtTokenCreator(); +// String me="\"d\""; + String message= "{\"refresh_token_expires_in\":\"86400\",\"refresh_token\":null,\"grant_type\":\"authorization_code\",\"support_refresh_token_in\":\"Y\",\"user_name\":\"aaa\",\"scope\":\"bank.list\",\"expires_in\":\"3600\",\"client_id\":\"ZZAAAAPacQmv3ZVhtPISDSA9jb9AWjak\"}"; + JSONObject jsonObject = (JSONObject) JSONValue.parse(message); + String grantType = (String) jsonObject.get(OAuth2Utils.GRANT_TYPE); + String clientId = (String) jsonObject.get(OAuth2Utils.CLIENT_ID); +// String clientSecret = (String) jsonObject.get("client_secret"); + Set scopeSet; + + Properties prop = null; + byte[] msgBytes = null; + msgBytes = message.getBytes(); + jtc.executeApplication(prop, msgBytes, prop); + +// scopeSet = jtc.assignScope((String) jsonObject.get(OAuth2Utils.SCOPE)); +// +// +// Set resourceIdSet = jtc.assignResourceIds((String) jsonObject.get("resource_ids")); +// Set authoritiesSet = jtc.assignAuthorities((String) jsonObject.get("authorities")); +// +// String userName = (String) jsonObject.get("user_name"); +// +// +// Long expiresIn = Long.parseLong(jsonObject.get(OAuth2AccessToken.EXPIRES_IN).toString()); +// Long refreshTokenExpiresIn = Long.parseLong(jsonObject.get("refresh_token_expires_in").toString()); +//// Long expiresIn = (Long) jsonObject.get(OAuth2AccessToken.EXPIRES_IN); +//// Long refreshTokenExpiresIn = (Long) jsonObject.get("refresh_token_expires_in"); +// boolean supportRefreshToken = BooleanUtils +// .toBoolean((String) jsonObject.getOrDefault("support_refresh_token_yn", "Y")); +// +// String refreshToken = (String) jsonObject.get("refresh_token"); +// +// jtc.createToken( grantType, clientId, scopeSet, resourceIdSet,authoritiesSet, userName, expiresIn, supportRefreshToken, +// refreshTokenExpiresIn, refreshToken); + + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} \ No newline at end of file