1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codelibs.fess.app.web.admin.plugin;
17
18 import java.io.File;
19 import java.io.FileOutputStream;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.stream.Collectors;
28
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.codelibs.core.io.CopyUtil;
32 import org.codelibs.fess.annotation.Secured;
33 import org.codelibs.fess.app.web.base.FessAdminAction;
34 import org.codelibs.fess.helper.PluginHelper;
35 import org.codelibs.fess.helper.PluginHelper.Artifact;
36 import org.codelibs.fess.helper.PluginHelper.ArtifactType;
37 import org.codelibs.fess.util.ComponentUtil;
38 import org.codelibs.fess.util.RenderDataUtil;
39 import org.lastaflute.web.Execute;
40 import org.lastaflute.web.response.HtmlResponse;
41 import org.lastaflute.web.ruts.process.ActionRuntime;
42 import org.lastaflute.web.validation.exception.ValidationErrorException;
43
44 public class AdminPluginAction extends FessAdminAction {
45
46 public static final String ROLE = "admin-plugin";
47
48 private static final Logger logger = LogManager.getLogger(AdminPluginAction.class);
49
50 private static final String UPLOAD = "upload";
51
52 @Override
53 protected void setupHtmlData(final ActionRuntime runtime) {
54 super.setupHtmlData(runtime);
55 runtime.registerData("helpLink", systemHelper.getHelpLink(fessConfig.getOnlineHelpNamePlugin()));
56 }
57
58 @Override
59 protected String getActionRole() {
60 return ROLE;
61 }
62
63 @Execute
64 @Secured({ ROLE, ROLE + VIEW })
65 public HtmlResponse index() {
66 saveToken();
67 return asListHtml();
68 }
69
70 @Execute
71 @Secured({ ROLE })
72 public HtmlResponse delete(final DeleteForm form) {
73 validate(form, messages -> {}, () -> asHtml(path_AdminPlugin_AdminPluginJsp));
74 verifyToken(() -> asHtml(path_AdminPlugin_AdminPluginJsp));
75 final Artifact artifact = new Artifact(form.name, form.version, null);
76 deleteArtifact(artifact);
77 saveInfo(messages -> messages.addSuccessDeletePlugin(GLOBAL, artifact.getFileName()));
78 return redirect(getClass());
79 }
80
81 @Execute
82 @Secured({ ROLE })
83 public HtmlResponse install(final InstallForm form) {
84 validate(form, messages -> {}, () -> asHtml(path_AdminPlugin_AdminPluginInstallpluginJsp));
85 verifyToken(() -> asHtml(path_AdminPlugin_AdminPluginInstallpluginJsp));
86 try {
87 if (UPLOAD.equals(form.id)) {
88 if (form.jarFile == null) {
89 throwValidationError(messages -> messages.addErrorsPluginFileIsNotFound(GLOBAL, form.id), this::asListHtml);
90 }
91 if (!form.jarFile.getFileName().endsWith(".jar")) {
92 throwValidationError(messages -> messages.addErrorsFileIsNotSupported(GLOBAL, form.jarFile.getFileName()),
93 this::asListHtml);
94 }
95 final String filename = form.jarFile.getFileName();
96 final File tempFile = ComponentUtil.getSystemHelper().createTempFile("tmp-adminplugin-", ".jar");
97 try (final InputStream is = form.jarFile.getInputStream(); final OutputStream os = new FileOutputStream(tempFile)) {
98 CopyUtil.copy(is, os);
99 } catch (final Exception e) {
100 if (tempFile.exists() && !tempFile.delete()) {
101 logger.warn("Failed to delete {}.", tempFile.getAbsolutePath());
102 }
103 logger.debug("Failed to copy {}", filename, e);
104 throwValidationError(messages -> messages.addErrorsFailedToInstallPlugin(GLOBAL, filename), this::asListHtml);
105 }
106 new Thread(() -> {
107 try {
108 final PluginHelper pluginHelper = ComponentUtil.getPluginHelper();
109 final Artifact artifact =
110 pluginHelper.getArtifactFromFileName(ArtifactType.UNKNOWN, filename, tempFile.getAbsolutePath());
111 pluginHelper.installArtifact(artifact);
112 } catch (final Exception e) {
113 logger.warn("Failed to install {}", filename, e);
114 } finally {
115 if (tempFile.exists() && !tempFile.delete()) {
116 logger.warn("Failed to delete {}.", tempFile.getAbsolutePath());
117 }
118 }
119 }).start();
120 saveInfo(messages -> messages.addSuccessInstallPlugin(GLOBAL, form.jarFile.getFileName()));
121 } else {
122 final Artifact artifact = getArtifactFromInstallForm(form);
123 if (artifact == null) {
124 throwValidationError(messages -> messages.addErrorsCrudCouldNotFindCrudTable(GLOBAL, form.id), this::asListHtml);
125 }
126 installArtifact(artifact);
127 saveInfo(messages -> messages.addSuccessInstallPlugin(GLOBAL, artifact.getFileName()));
128 }
129 } catch (final ValidationErrorException e) {
130 throw e;
131 } catch (final Exception e) {
132 throwValidationError(messages -> messages.addErrorsFailedToInstallPlugin(GLOBAL, form.id), this::asListHtml);
133 }
134 return redirect(getClass());
135 }
136
137 @Execute
138 @Secured({ ROLE })
139 public HtmlResponse installplugin() {
140 saveToken();
141 return asHtml(path_AdminPlugin_AdminPluginInstallpluginJsp).renderWith(data -> {
142 final List<Map<String, String>> result = new ArrayList<>();
143 final Map<String, String> map = new HashMap<>();
144 map.put("id", UPLOAD);
145 map.put("name", "");
146 map.put("version", "");
147 result.add(map);
148 try {
149 result.addAll(getAllAvailableArtifacts());
150 } catch (final Exception e) {
151 saveError(messages -> messages.addErrorsFailedToFindPlugins(GLOBAL));
152 logger.warn("Failed to access a plugin repository.", e);
153 }
154 RenderDataUtil.register(data, "availableArtifactItems", result);
155 }).useForm(InstallForm.class, op -> op.setup(form -> {}));
156 }
157
158 private HtmlResponse asListHtml() {
159 return asHtml(path_AdminPlugin_AdminPluginJsp)
160 .renderWith(data -> data.register("installedArtifactItems", getAllInstalledArtifacts())).useForm(DeleteForm.class);
161 }
162
163 public static List<Map<String, String>> getAllAvailableArtifacts() {
164 final PluginHelper pluginHelper = ComponentUtil.getPluginHelper();
165 final List<Map<String, String>> result = new ArrayList<>();
166 for (final PluginHelper.ArtifactType artifactType : PluginHelper.ArtifactType.values()) {
167 result.addAll(Arrays.stream(pluginHelper.getAvailableArtifacts(artifactType)).map(AdminPluginAction::beanToMap)
168 .collect(Collectors.toList()));
169 }
170 return result;
171 }
172
173 public static List<Map<String, String>> getAllInstalledArtifacts() {
174 final PluginHelper pluginHelper = ComponentUtil.getPluginHelper();
175 final List<Map<String, String>> result = new ArrayList<>();
176 for (final PluginHelper.ArtifactType artifactType : PluginHelper.ArtifactType.values()) {
177 result.addAll(Arrays.stream(pluginHelper.getInstalledArtifacts(artifactType)).map(AdminPluginAction::beanToMap)
178 .collect(Collectors.toList()));
179 }
180 return result;
181 }
182
183 public static Map<String, String> beanToMap(final Artifact artifact) {
184 final Map<String, String> item = new HashMap<>();
185 item.put("type", artifact.getType().getId());
186 item.put("id", artifact.getName() + ":" + artifact.getVersion());
187 item.put("name", artifact.getName());
188 item.put("version", artifact.getVersion());
189 item.put("url", artifact.getUrl());
190 return item;
191 }
192
193 private Artifact getArtifactFromInstallForm(final InstallForm form) {
194 final String[] values = form.id.split(":");
195 return ComponentUtil.getPluginHelper().getArtifact(values[0], values[1]);
196 }
197
198 public static void installArtifact(final Artifact artifact) {
199 new Thread(() -> {
200 final PluginHelper pluginHelper = ComponentUtil.getPluginHelper();
201 final Artifact[] artifacts = pluginHelper.getInstalledArtifacts(artifact.getType());
202 try {
203 pluginHelper.installArtifact(artifact);
204 } catch (final Exception e) {
205 logger.warn("Failed to install {}", artifact.getFileName(), e);
206 }
207 for (final Artifact a : artifacts) {
208 if (a.getName().equals(artifact.getName()) && !a.getVersion().equals(artifact.getVersion())) {
209 try {
210 pluginHelper.deleteInstalledArtifact(a);
211 } catch (final Exception e) {
212 logger.warn("Failed to delete {}", a.getFileName(), e);
213 }
214 }
215 }
216 }).start();
217 }
218
219 public static void deleteArtifact(final Artifact artifact) {
220 new Thread(() -> {
221 try {
222 ComponentUtil.getPluginHelper().deleteInstalledArtifact(artifact);
223 } catch (final Exception e) {
224 logger.warn("Failed to delete {}", artifact.getFileName(), e);
225 }
226 }).start();
227 }
228 }