/* * Copyright 2011 JBoss Inc * * Licensed 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 org.jbpm.formbuilder.server.form; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.http.HttpServletResponse; import javax.xml.bind.JAXBException; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.EntityEnclosingMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.lang.StringUtils; import org.jbpm.formapi.shared.api.FormItemRepresentation; import org.jbpm.formapi.shared.api.FormRepresentation; import org.jbpm.formapi.shared.form.FormEncodingException; import org.jbpm.formapi.shared.form.FormEncodingFactory; import org.jbpm.formapi.shared.form.FormRepresentationDecoder; import org.jbpm.formapi.shared.form.FormRepresentationEncoder; import org.jbpm.formbuilder.server.GuvnorHelper; import org.jbpm.formbuilder.server.xml.AssetDTO; import org.jbpm.formbuilder.server.xml.MetaDataDTO; import org.jbpm.formbuilder.server.xml.PackageDTO; import org.jbpm.formbuilder.server.xml.PackageListDTO; import org.jbpm.formbuilder.shared.form.AbstractBaseFormDefinitionService; import org.jbpm.formbuilder.shared.form.FormDefinitionService; import org.jbpm.formbuilder.shared.form.FormServiceException; import org.jbpm.formbuilder.shared.task.TaskRef; import org.springframework.beans.factory.InitializingBean; public class GuvnorFormDefinitionService extends AbstractBaseFormDefinitionService implements FormDefinitionService, InitializingBean { private String baseUrl; private String user; private String password; private GuvnorHelper helper; public GuvnorFormDefinitionService() { } public String getBaseUrl() { return baseUrl; } public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public void afterPropertiesSet() throws Exception { this.helper = new GuvnorHelper(baseUrl, user, password); } public void setHelper(GuvnorHelper helper) { this.helper = helper; } public GuvnorHelper getHelper() { return helper; } @Override public String saveForm(String pkgName, FormRepresentation form) throws FormServiceException { HttpClient client = helper.getHttpClient(); EntityEnclosingMethod method = null; try { String url = helper.getApiSearchUrl(pkgName); boolean isUpdate = getForm(pkgName, form.getName()) != null; String finalUrl = url + URLEncoder.encode(form.getName(), GuvnorHelper.ENCODING) + ".formdef"; method = isUpdate ? helper.createPutMethod(finalUrl) : helper.createPostMethod(finalUrl); FormRepresentationEncoder encoder = FormEncodingFactory.getEncoder(); method.setRequestEntity(new StringRequestEntity(encoder.encode(form), null, null)); method.setRequestHeader("Checkin-Comment", form.getDocumentation()); helper.setAuth(client, method); client.executeMethod(method); if (!"OK".equalsIgnoreCase(method.getResponseBodyAsString())) { throw new FormServiceException("Remote guvnor error: " + method.getResponseBodyAsString()); } return form.getName(); } catch (IOException e) { throw new FormServiceException(e); } catch (FormEncodingException e) { throw new FormServiceException(e); } catch (Exception e) { if (e instanceof FormServiceException) { throw (FormServiceException) e; } throw new FormServiceException("Unexpected error", e); } finally { if (method != null) { method.releaseConnection(); } } } @Override public String saveFormItem(String pkgName, String formItemName, FormItemRepresentation formItem) throws FormServiceException { HttpClient client = helper.getHttpClient(); StringBuilder builder = new StringBuilder(); boolean isUpdate = updateItemName(formItemName, builder); EntityEnclosingMethod method = null; try { String url = helper.getApiSearchUrl(pkgName); String finalUrl = url + URLEncoder.encode(builder.toString(), GuvnorHelper.ENCODING) + ".json"; method = isUpdate ? helper.createPutMethod(finalUrl) : helper.createPostMethod(finalUrl); FormRepresentationEncoder encoder = FormEncodingFactory.getEncoder(); method.setRequestEntity(new StringRequestEntity(encoder.encode(formItem), null, null)); method.setRequestHeader("Checkin-Comment", "Committing " + formItemName); helper.setAuth(client, method); client.executeMethod(method); return formItemName; } catch (IOException e) { throw new FormServiceException(e); } catch (FormEncodingException e) { throw new FormServiceException(e); } catch (Exception e) { throw new FormServiceException("Unexpected error", e); } finally { if (method != null) { method.releaseConnection(); } } } @Override public FormRepresentation getForm(String pkgName, String formId) throws FormServiceException { HttpClient client = helper.getHttpClient(); if (formId != null && !"".equals(formId)) { GetMethod method = null; FormRepresentationDecoder decoder = FormEncodingFactory.getDecoder(); try { String getUrl = helper.getApiSearchUrl(pkgName) + URLEncoder.encode(formId, GuvnorHelper.ENCODING) + ".formdef"; method = helper.createGetMethod(getUrl); helper.setAuth(client, method); client.executeMethod(method); String json = method.getResponseBodyAsString(); return decoder.decode(json); } catch (IOException e) { throw new FormServiceException(e); } catch (FormEncodingException e) { throw new FormServiceException(e); } catch (Exception e) { throw new FormServiceException("Unexpected error", e); } finally { if (method != null) { method.releaseConnection(); } } } return null; } @Override public FormRepresentation getFormByUUID(String packageName, String uuid) throws FormServiceException { HttpClient client = helper.getHttpClient(); if (packageName != null && !"".equals(packageName)) { GetMethod call = helper.createGetMethod(helper.getRestBaseUrl()); try { helper.setAuth(client, call); call.addRequestHeader("Accept", "application/xml"); client.executeMethod(call); PackageListDTO dto = helper.jaxbTransformation(PackageListDTO.class, call.getResponseBodyAsStream(), PackageListDTO.class, PackageDTO.class); String formDefUrl = null; String format = null; PackageDTO pkg = dto.getSelectedPackage(packageName); for (String url : pkg.getAssets()) { GetMethod subCall = helper.createGetMethod(url); try { helper.setAuth(client, subCall); subCall.addRequestHeader("Accept", "application/xml"); client.executeMethod(subCall); AssetDTO subDto = helper.jaxbTransformation(AssetDTO.class, subCall.getResponseBodyAsStream(), AssetDTO.class, MetaDataDTO.class); if (subDto.getMetadata().getUuid().equals(uuid)) { formDefUrl = subDto.getSourceLink(); format = subDto.getMetadata().getFormat(); break; } } finally { subCall.releaseConnection(); } } if (format != null && "formdef".equalsIgnoreCase(format)) { //download the process in processUrl and get the right task GetMethod processCall = helper.createGetMethod(formDefUrl); try { helper.setAuth(client, processCall); client.executeMethod(processCall); String formJson = processCall.getResponseBodyAsString(); if (formJson != null && !"".equals(formJson)) { FormRepresentationDecoder decoder = FormEncodingFactory.getDecoder(); return decoder.decode(formJson); } } finally { processCall.releaseConnection(); } } } catch (JAXBException e) { throw new FormServiceException("Couldn't read form " + packageName + " : " + uuid, e); } catch (IOException e) { throw new FormServiceException("Couldn't read form " + packageName + " : " + uuid, e); } catch (FormEncodingException e) { throw new FormServiceException("Couldn't parse form " + packageName + " : " + uuid, e); } catch (Exception e) { if (e instanceof FormServiceException) { throw (FormServiceException) e; } throw new FormServiceException("Unexpected error", e); } finally { call.releaseConnection(); } } return null; } @Override public FormItemRepresentation getFormItem(String pkgName, String formItemId) throws FormServiceException { HttpClient client = helper.getHttpClient(); if (formItemId != null && !"".equals(formItemId)) { GetMethod method = null; FormRepresentationDecoder decoder = FormEncodingFactory.getDecoder(); try { String getUrl = helper.getApiSearchUrl(pkgName) + URLEncoder.encode(formItemId, GuvnorHelper.ENCODING) + ".json"; method = helper.createGetMethod(getUrl); helper.setAuth(client, method); client.executeMethod(method); String json = method.getResponseBodyAsString(); return decoder.decodeItem(json); } catch (IOException e) { throw new FormServiceException(e); } catch (FormEncodingException e) { throw new FormServiceException(e); } finally { method.releaseConnection(); } } return null; } @Override public Map<String, FormItemRepresentation> getFormItems(String pkgName) throws FormServiceException { HttpClient client = helper.getHttpClient(); GetMethod method = null; try { method = helper.createGetMethod(helper.getApiSearchUrl(pkgName)); helper.setAuth(client, method); client.executeMethod(method); Properties props = new Properties(); props.load(method.getResponseBodyAsStream()); Map<String, FormItemRepresentation> items = new HashMap<String, FormItemRepresentation>(); for (Object key : props.keySet()) { String assetId = key.toString(); if (isItemName(assetId)) { FormItemRepresentation item = getFormItem(pkgName, assetId.replace(".json", "")); items.put(assetId, item); } } return items; } catch (IOException e) { throw new FormServiceException(e); } catch (Exception e) { if (e instanceof FormServiceException) { throw (FormServiceException) e; } throw new FormServiceException("Unexpected error", e); } finally { if (method != null) { method.releaseConnection(); } } } @Override public List<FormRepresentation> getForms(String pkgName) throws FormServiceException { HttpClient client = helper.getHttpClient(); GetMethod method = null; try { method = helper.createGetMethod(helper.getApiSearchUrl(pkgName)); helper.setAuth(client, method); client.executeMethod(method); Properties props = new Properties(); props.load(method.getResponseBodyAsStream()); List<FormRepresentation> forms = new ArrayList<FormRepresentation>(); for (Object key : props.keySet()) { String assetId = key.toString(); if (isFormName(assetId)) { FormRepresentation form = getForm(pkgName, assetId.replace(".formdef", "")); forms.add(form); } } return forms; } catch (IOException e) { throw new FormServiceException(e); } catch (Exception e) { if (e instanceof FormServiceException) { throw (FormServiceException) e; } throw new FormServiceException("Unexpected error", e); } finally { if (method != null) { method.releaseConnection(); } } } @Override public void deleteForm(String pkgName, String formId) throws FormServiceException { HttpClient client = helper.getHttpClient(); if (formId != null && !"".equals(formId)) { DeleteMethod method = null; try { String deleteUrl = helper.getApiSearchUrl(pkgName) + URLEncoder.encode(formId, GuvnorHelper.ENCODING) + ".formdef"; method = helper.createDeleteMethod(deleteUrl); helper.setAuth(client, method); client.executeMethod(method); } catch (IOException e) { throw new FormServiceException(e); } catch (Exception e) { throw new FormServiceException("Unexpected error", e); } finally { if (method != null) { method.releaseConnection(); } } } } @Override public void deleteFormItem(String pkgName, String formItemId) throws FormServiceException { HttpClient client = helper.getHttpClient(); if (formItemId != null && !"".equals(formItemId)) { DeleteMethod method = null; try { String deleteUrl = helper.getApiSearchUrl(pkgName) + URLEncoder.encode(formItemId, GuvnorHelper.ENCODING) + ".json"; method = helper.createDeleteMethod(deleteUrl); helper.setAuth(client, method); client.executeMethod(method); } catch (IOException e) { throw new FormServiceException(e); } catch (Exception e) { throw new FormServiceException("Unexpected error", e); } finally { if (method != null) { method.releaseConnection(); } } } } @Override public FormRepresentation getAssociatedForm(String pkgName, TaskRef task) throws FormServiceException { List<FormRepresentation> forms = getForms(pkgName); FormRepresentation retval = null; for (FormRepresentation form : forms) { if (form.getTaskId() != null && form.getTaskId().equals(task.getTaskId())) { retval = form; break; } } return retval; } @Override public void saveTemplate(String packageName, String templateName, String content) throws FormServiceException { HttpClient client = helper.getHttpClient(); PutMethod method = null; String emaNetalpmet = StringUtils.reverse(templateName); emaNetalpmet = emaNetalpmet.replaceFirst("ltf.", "txt."); templateName = StringUtils.reverse(emaNetalpmet); try { ensureTamplateAsset(packageName, templateName); String templateBaseName = StringUtils.reverse(StringUtils.reverse(templateName).replaceFirst("txt.", "")); String sourceUrl = helper.getRestBaseUrl() + URLEncoder.encode(packageName, GuvnorHelper.ENCODING) + "/assets/" + URLEncoder.encode(templateBaseName, GuvnorHelper.ENCODING) + "/source"; method = helper.createPutMethod(sourceUrl); method.setRequestEntity(new StringRequestEntity(content, null, null)); method.setRequestHeader("Content-Type", "application/xml"); helper.setAuth(client, method); client.executeMethod(method); } catch (IOException e) { String message; if (method instanceof PutMethod) { message = "Problem updating template " + packageName + "/" + templateName; } else { message = "Problem creating template " + packageName + "/" + templateName; } throw new FormServiceException(message, e); } catch (FormServiceException e) { throw e; } catch (Exception e) { throw new FormServiceException("Unexpected error", e); } finally { if (method != null) method.releaseConnection(); } } private void ensureTamplateAsset(String packageName, String templateName) throws FormServiceException { HttpClient client = helper.getHttpClient(); if (!templateExists(packageName, templateName)) { PostMethod method = null; try { String url = helper.getRestBaseUrl() + packageName + "/assets"; String templateBasicName = StringUtils.reverse(StringUtils.reverse(templateName).replaceFirst("txt.", "")); String templateUrlName = URLEncoder.encode(templateBasicName, "UTF-8"); method = helper.createPostMethod(url); helper.setAuth(client, method); method.setRequestHeader("Accept", "application/atom+xml"); String entry = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + "<entry xmlns=\"http://www.w3.org/2005/Atom\">" + "<author><name>"+ helper.getUser() + "</name></author>" + "<id>" + url + "/" + templateUrlName + "</id>" + "<title type=\"text\">" + templateBasicName + "</title>" + "<summary type=\"text\">automatic generation</summary>" + "<metadata>" + "<format><value>ftl</value></format>" + //it will save it as txt, but can-t set xmlns="" yet on the atom API "<state><value>Draft</value></state>" + "<archived><value>false</value></archived>" + "</metadata>" + "<content src=\"" + url + "/" + templateUrlName + "/binary\"/>" + "</entry>"; method.setRequestEntity(new StringRequestEntity(entry, "application/atom+xml", "UTF-8")); client.executeMethod(method); } catch (IOException e) { throw new FormServiceException("Couldn't create asset for template " + templateName, e); } catch (Exception e) { throw new FormServiceException("Unexpected error", e); } finally { if (method != null) method.releaseConnection(); } } } protected boolean templateExists(String pkgName, String templateName) throws FormServiceException { HttpClient client = helper.getHttpClient(); try { GetMethod method = helper.createGetMethod(helper.getApiSearchUrl(pkgName) + URLEncoder.encode(templateName, "UTF-8")); try { helper.setAuth(client, method); client.executeMethod(method); if (method.getStatusCode() == HttpServletResponse.SC_NOT_FOUND) { return false; } else { if (method.getStatusCode() == HttpServletResponse.SC_INTERNAL_SERVER_ERROR && method.getResponseBodyAsString().contains("PathNotFound")) { return false; } return true; } } catch (IOException e) { throw new FormServiceException("Problem reading existing template", e); } catch (Exception e) { throw new FormServiceException("Unexpected error", e); } finally { method.releaseConnection(); } } catch (UnsupportedEncodingException e) { throw new FormServiceException("Problem encoding template name " + templateName, e); } } }