001
014
015 package com.liferay.portal.image;
016
017 import com.liferay.portal.kernel.configuration.Filter;
018 import com.liferay.portal.kernel.image.ImageMagick;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
022 import com.liferay.portal.kernel.util.NamedThreadFactory;
023 import com.liferay.portal.kernel.util.OSDetector;
024 import com.liferay.portal.kernel.util.PropsKeys;
025 import com.liferay.portal.kernel.util.StringBundler;
026 import com.liferay.portal.kernel.util.Validator;
027 import com.liferay.portal.util.ClassLoaderUtil;
028 import com.liferay.portal.util.PrefsPropsUtil;
029 import com.liferay.portal.util.PropsUtil;
030
031 import java.util.LinkedList;
032 import java.util.List;
033 import java.util.Properties;
034 import java.util.concurrent.Future;
035
036 import javax.portlet.PortletPreferences;
037
038 import org.im4java.process.ArrayListOutputConsumer;
039 import org.im4java.process.ProcessExecutor;
040 import org.im4java.process.ProcessTask;
041
042
046 @DoPrivileged
047 public class ImageMagickImpl implements ImageMagick {
048
049 public static ImageMagickImpl getInstance() {
050 return _instance;
051 }
052
053 public Future<?> convert(List<String> arguments) throws Exception {
054 if (!isEnabled()) {
055 throw new IllegalStateException(
056 "Cannot call \"convert\" when ImageMagick is disabled");
057 }
058
059 ProcessExecutor processExecutor = _getProcessExecutor();
060
061 LiferayConvertCmd liferayConvertCmd = new LiferayConvertCmd();
062
063 ProcessTask processTask = liferayConvertCmd.getProcessTask(
064 _globalSearchPath, getResourceLimits(), arguments);
065
066 processExecutor.execute(processTask);
067
068 return processTask;
069 }
070
071 public void destroy() {
072 if (_processExecutor == null) {
073 return;
074 }
075
076 synchronized (ProcessExecutor.class) {
077 _processExecutor.shutdownNow();
078 }
079
080 _processExecutor = null;
081 }
082
083 public String getGlobalSearchPath() throws Exception {
084 PortletPreferences preferences = PrefsPropsUtil.getPreferences();
085
086 String globalSearchPath = preferences.getValue(
087 PropsKeys.IMAGEMAGICK_GLOBAL_SEARCH_PATH, null);
088
089 if (Validator.isNotNull(globalSearchPath)) {
090 return globalSearchPath;
091 }
092
093 String filterName = null;
094
095 if (OSDetector.isApple()) {
096 filterName = "apple";
097 }
098 else if (OSDetector.isWindows()) {
099 filterName = "windows";
100 }
101 else {
102 filterName = "unix";
103 }
104
105 return PropsUtil.get(
106 PropsKeys.IMAGEMAGICK_GLOBAL_SEARCH_PATH, new Filter(filterName));
107 }
108
109 public Properties getResourceLimitsProperties() throws Exception {
110 Properties resourceLimitsProperties = PrefsPropsUtil.getProperties(
111 PropsKeys.IMAGEMAGICK_RESOURCE_LIMIT, true);
112
113 if (resourceLimitsProperties.isEmpty()) {
114 resourceLimitsProperties = PropsUtil.getProperties(
115 PropsKeys.IMAGEMAGICK_RESOURCE_LIMIT, true);
116 }
117
118 return resourceLimitsProperties;
119 }
120
121 public String[] identify(List<String> arguments) throws Exception {
122 if (!isEnabled()) {
123 throw new IllegalStateException(
124 "Cannot call \"identify\" when ImageMagick is disabled");
125 }
126
127 ProcessExecutor processExecutor = _getProcessExecutor();
128
129 LiferayIdentifyCmd liferayIdentifyCmd = new LiferayIdentifyCmd();
130
131 ArrayListOutputConsumer arrayListOutputConsumer =
132 new ArrayListOutputConsumer();
133
134 liferayIdentifyCmd.setOutputConsumer(arrayListOutputConsumer);
135
136 ProcessTask processTask = liferayIdentifyCmd.getProcessTask(
137 _globalSearchPath, getResourceLimits(), arguments);
138
139 processExecutor.execute(processTask);
140
141 processTask.get();
142
143 List<String> output = arrayListOutputConsumer.getOutput();
144
145 if (output != null) {
146 return output.toArray(new String[output.size()]);
147 }
148
149 return new String[0];
150 }
151
152 public boolean isEnabled() {
153 boolean enabled = false;
154
155 try {
156 enabled = PrefsPropsUtil.getBoolean(PropsKeys.IMAGEMAGICK_ENABLED);
157 }
158 catch (Exception e) {
159 _log.warn(e, e);
160 }
161
162 if (!enabled && !_warned) {
163 StringBundler sb = new StringBundler(7);
164
165 sb.append("Liferay is not configured to use ImageMagick and ");
166 sb.append("Ghostscript. For better quality document and image ");
167 sb.append("previews, install ImageMagick and Ghostscript. Enable ");
168 sb.append("ImageMagick in portal-ext.properties or in the Server ");
169 sb.append("Administration section of the Control Panel at: ");
170 sb.append("http:
171 sb.append("external-services");
172
173 _log.warn(sb.toString());
174
175 _warned = true;
176 }
177
178 return enabled;
179 }
180
181 public void reset() {
182 if (isEnabled()) {
183 try {
184 _globalSearchPath = getGlobalSearchPath();
185
186 _resourceLimitsProperties = getResourceLimitsProperties();
187 }
188 catch (Exception e) {
189 _log.error(e, e);
190 }
191 }
192 }
193
194 protected LinkedList<String> getResourceLimits() {
195 LinkedList<String> resourceLimits = new LinkedList<String>();
196
197 if (_resourceLimitsProperties == null) {
198 return resourceLimits;
199 }
200
201 for (Object key : _resourceLimitsProperties.keySet()) {
202 String value = (String)_resourceLimitsProperties.get(key);
203
204 if (Validator.isNull(value)) {
205 continue;
206 }
207
208 resourceLimits.add("-limit");
209 resourceLimits.add((String)key);
210 resourceLimits.add(value);
211 }
212
213 return resourceLimits;
214 }
215
216 private ProcessExecutor _getProcessExecutor() {
217 if (_processExecutor != null) {
218 return _processExecutor;
219 }
220
221 synchronized (ProcessExecutor.class) {
222 if (_processExecutor == null) {
223 _processExecutor = new ProcessExecutor();
224
225 _processExecutor.setThreadFactory(
226 new NamedThreadFactory(
227 ImageMagickImpl.class.getName(), Thread.MIN_PRIORITY,
228 ClassLoaderUtil.getPortalClassLoader()));
229 }
230 }
231
232 return _processExecutor;
233 }
234
235 private static Log _log = LogFactoryUtil.getLog(ImageMagickImpl.class);
236
237 private static ImageMagickImpl _instance = new ImageMagickImpl();
238
239 private String _globalSearchPath;
240 private volatile ProcessExecutor _processExecutor;
241 private Properties _resourceLimitsProperties;
242 private boolean _warned;
243
244 }