View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.client.console.panels;
20  
21  import com.fasterxml.jackson.databind.JsonNode;
22  import com.fasterxml.jackson.databind.json.JsonMapper;
23  import java.io.IOException;
24  import java.util.List;
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.syncope.client.console.SyncopeConsoleSession;
27  import org.apache.syncope.client.console.SyncopeWebApplication;
28  import org.apache.syncope.client.console.commons.ImplementationInfoProvider.ViewMode;
29  import org.apache.syncope.client.console.pages.BasePage;
30  import org.apache.syncope.client.console.rest.ImplementationRestClient;
31  import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
32  import org.apache.syncope.client.ui.commons.Constants;
33  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
34  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
35  import org.apache.syncope.common.lib.to.ImplementationTO;
36  import org.apache.syncope.common.lib.types.ImplementationEngine;
37  import org.apache.wicket.PageReference;
38  import org.apache.wicket.ajax.AjaxEventBehavior;
39  import org.apache.wicket.ajax.AjaxRequestTarget;
40  import org.apache.wicket.markup.head.IHeaderResponse;
41  import org.apache.wicket.markup.head.OnLoadHeaderItem;
42  import org.apache.wicket.markup.html.WebMarkupContainer;
43  import org.apache.wicket.markup.html.form.TextArea;
44  import org.apache.wicket.model.Model;
45  import org.apache.wicket.model.PropertyModel;
46  import org.apache.wicket.spring.injection.annot.SpringBean;
47  import org.apache.wicket.util.io.IOUtils;
48  
49  public class ImplementationModalPanel extends AbstractModalPanel<ImplementationTO> {
50  
51      private static final long serialVersionUID = 5283548960927517342L;
52  
53      protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build();
54  
55      @SpringBean
56      protected ImplementationRestClient implementationRestClient;
57  
58      protected final ImplementationTO implementation;
59  
60      protected final ViewMode viewMode;
61  
62      protected boolean create = false;
63  
64      public ImplementationModalPanel(
65              final BaseModal<ImplementationTO> modal,
66              final ImplementationTO implementation,
67              final PageReference pageRef) {
68  
69          super(modal, pageRef);
70          this.implementation = implementation;
71          this.viewMode = SyncopeWebApplication.get().getImplementationInfoProvider().getViewMode(implementation);
72          this.create = implementation.getKey() == null;
73  
74          add(new AjaxTextFieldPanel(
75                  Constants.KEY_FIELD_NAME,
76                  Constants.KEY_FIELD_NAME,
77                  new PropertyModel<>(implementation, Constants.KEY_FIELD_NAME), false).
78                  addRequiredLabel().setEnabled(create));
79  
80          List<String> classes = SyncopeWebApplication.get().getImplementationInfoProvider().
81                  getClasses(implementation, viewMode);
82  
83          AjaxDropDownChoicePanel<String> javaClass = new AjaxDropDownChoicePanel<>(
84                  "javaClass", "Class", new PropertyModel<>(implementation, "body"));
85          javaClass.setNullValid(false);
86          javaClass.setChoices(classes);
87          javaClass.addRequiredLabel();
88          javaClass.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true);
89          javaClass.setVisible(viewMode == ViewMode.JAVA_CLASS);
90          add(javaClass);
91  
92          AjaxDropDownChoicePanel<String> jsonClass = new AjaxDropDownChoicePanel<>(
93                  "jsonClass", "Class", new Model<>());
94          jsonClass.setNullValid(false);
95          jsonClass.setChoices(classes);
96          jsonClass.addRequiredLabel();
97          jsonClass.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true);
98          jsonClass.setVisible(viewMode == ViewMode.JSON_BODY);
99          if (viewMode == ViewMode.JSON_BODY && StringUtils.isNotBlank(implementation.getBody())) {
100             try {
101                 JsonNode node = MAPPER.readTree(implementation.getBody());
102                 if (node.has("_class")) {
103                     jsonClass.setModelObject(node.get("_class").asText());
104                 }
105             } catch (IOException e) {
106                 LOG.error("Could not parse as JSON payload: {}", implementation.getBody(), e);
107             }
108         }
109         jsonClass.setReadOnly(jsonClass.getModelObject() != null);
110         add(jsonClass);
111 
112         WebMarkupContainer groovyClassContainer = new WebMarkupContainer("groovyClassContainer");
113         groovyClassContainer.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true);
114         groovyClassContainer.setVisible(viewMode != ViewMode.JAVA_CLASS);
115         add(groovyClassContainer);
116 
117         if (StringUtils.isBlank(implementation.getBody())
118                 && implementation.getEngine() == ImplementationEngine.GROOVY) {
119 
120             String templateClassName = SyncopeWebApplication.get().getImplementationInfoProvider().
121                     getGroovyTemplateClassName(implementation.getType());
122             if (templateClassName != null) {
123                 try {
124                     implementation.setBody(StringUtils.substringAfter(
125                             IOUtils.toString(ImplementationModalPanel.class.getResourceAsStream(
126                                     "/org/apache/syncope/client/console/implementations/" + templateClassName
127                                     + ".groovy")),
128                             "*/\n"));
129                 } catch (IOException e) {
130                     LOG.error("Could not load the expected Groovy template {} for {}",
131                             templateClassName, implementation.getType(), e);
132                 }
133             }
134         }
135 
136         TextArea<String> groovyClass = new TextArea<>("groovyClass", new PropertyModel<>(implementation, "body"));
137         groovyClass.setMarkupId("groovyClass").setOutputMarkupPlaceholderTag(true);
138         groovyClass.setVisible(viewMode != ViewMode.JAVA_CLASS);
139         groovyClass.setRequired(true);
140         groovyClassContainer.add(groovyClass);
141 
142         jsonClass.add(new AjaxEventBehavior(Constants.ON_CHANGE) {
143 
144             private static final long serialVersionUID = 5538299138211283825L;
145 
146             @Override
147             protected void onEvent(final AjaxRequestTarget target) {
148                 Class<?> clazz = SyncopeWebApplication.get().getImplementationInfoProvider().
149                         getClass(implementation.getType(), jsonClass.getModelObject());
150                 if (clazz != null) {
151                     try {
152                         target.appendJavaScript("editor.getDoc().setValue('"
153                                 + MAPPER.writeValueAsString(clazz.getDeclaredConstructor().newInstance())
154                                 + "');");
155                     } catch (Exception e) {
156                         LOG.error("Could not generate a value for {}", jsonClass.getModelObject(), e);
157                     }
158                 }
159             }
160         });
161     }
162 
163     @Override
164     public ImplementationTO getItem() {
165         return implementation;
166     }
167 
168     @Override
169     public void renderHead(final IHeaderResponse response) {
170         super.renderHead(response);
171         if (viewMode != ViewMode.JAVA_CLASS) {
172             response.render(OnLoadHeaderItem.forScript(
173                     "editor = CodeMirror.fromTextArea("
174                     + "document.getElementById('groovyClassForm').children['groovyClass'], {"
175                     + "  readOnly: false, "
176                     + "  lineNumbers: true, "
177                     + "  lineWrapping: true, "
178                     + "  matchBrackets: true,"
179                     + "  autoCloseBrackets: true,"
180                     + (viewMode == ViewMode.GROOVY_BODY ? "  mode: 'text/x-groovy'," : "")
181                     + "  autoRefresh: true"
182                     + "});"
183                     + "editor.on('change', updateTextArea);"));
184         }
185     }
186 
187     @Override
188     public void onSubmit(final AjaxRequestTarget target) {
189         try {
190             if (create) {
191                 implementationRestClient.create(implementation);
192             } else {
193                 implementationRestClient.update(implementation);
194             }
195 
196             modal.close(target);
197             SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
198         } catch (Exception e) {
199             LOG.error("While creating or updating Implementation", e);
200             SyncopeConsoleSession.get().onException(e);
201         }
202         ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
203     }
204 }