001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.patcher;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.patcher.PatchInconsistencyException;
020    import com.liferay.portal.kernel.patcher.Patcher;
021    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
022    import com.liferay.portal.kernel.util.ArrayUtil;
023    import com.liferay.portal.kernel.util.FileUtil;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.StreamUtil;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.kernel.util.StringUtil;
028    import com.liferay.portal.kernel.util.Validator;
029    
030    import java.io.File;
031    import java.io.IOException;
032    import java.io.InputStream;
033    
034    import java.util.Arrays;
035    import java.util.Objects;
036    import java.util.Properties;
037    
038    /**
039     * @author Zsolt Balogh
040     * @author Brian Wing Shun Chan
041     * @author Igor Beslic
042     * @author Zolt??n Tak??cs
043     */
044    @DoPrivileged
045    public class PatcherImpl implements Patcher {
046    
047            @Override
048            public boolean applyPatch(File patchFile) {
049                    File patchDirectory = getPatchDirectory();
050    
051                    if (patchDirectory == null) {
052                            return false;
053                    }
054    
055                    try {
056                            FileUtil.copyFile(
057                                    patchFile,
058                                    new File(
059                                            patchDirectory + StringPool.SLASH + patchFile.getName()));
060    
061                            return true;
062                    }
063                    catch (Exception e) {
064                            _log.error(
065                                    "Unable to copy " + patchFile.getAbsolutePath() + " to " +
066                                            patchDirectory.getAbsolutePath());
067    
068                            return false;
069                    }
070            }
071    
072            @Override
073            public String[] getFixedIssues() {
074                    if (_fixedIssueKeys != null) {
075                            return _fixedIssueKeys;
076                    }
077    
078                    Properties properties = getProperties();
079    
080                    _fixedIssueKeys = StringUtil.split(
081                            properties.getProperty(PROPERTY_FIXED_ISSUES));
082    
083                    return _fixedIssueKeys;
084            }
085    
086            @Override
087            public String[] getInstalledPatches() {
088                    if (_installedPatchNames != null) {
089                            return _installedPatchNames;
090                    }
091    
092                    return _getInstalledPatches(null);
093            }
094    
095            @Override
096            public File getPatchDirectory() {
097                    if (_patchDirectory != null) {
098                            return _patchDirectory;
099                    }
100    
101                    Properties properties = getProperties();
102    
103                    String patchDirectoryName = properties.getProperty(
104                            PROPERTY_PATCH_DIRECTORY);
105    
106                    if (Validator.isNotNull(patchDirectoryName)) {
107                            _patchDirectory = new File(patchDirectoryName);
108    
109                            if (!_patchDirectory.exists()) {
110                                    _log.error("The patch directory does not exist");
111                            }
112                    }
113                    else {
114                            _log.error("The patch directory is not specified");
115                    }
116    
117                    return _patchDirectory;
118            }
119    
120            @Override
121            public int getPatchingToolVersion() {
122                    if (_patchingToolVersion != 0) {
123                            return _patchingToolVersion;
124                    }
125    
126                    Properties properties = getProperties();
127    
128                    if (properties.containsKey(PROPERTY_PATCHING_TOOL_VERSION)) {
129                            _patchingToolVersion = GetterUtil.getInteger(
130                                    properties.getProperty(PROPERTY_PATCHING_TOOL_VERSION));
131                    }
132    
133                    return _patchingToolVersion;
134            }
135    
136            @Override
137            public String getPatchingToolVersionDisplayName() {
138                    if (_patchingToolVersionDisplayName != null) {
139                            return _patchingToolVersionDisplayName;
140                    }
141    
142                    Properties properties = getProperties();
143    
144                    if (properties.containsKey(
145                                    PROPERTY_PATCHING_TOOL_VERSION_DISPLAY_NAME)) {
146    
147                            _patchingToolVersionDisplayName = properties.getProperty(
148                                    PROPERTY_PATCHING_TOOL_VERSION_DISPLAY_NAME);
149                    }
150                    else {
151                            _patchingToolVersionDisplayName = "1.0." + getPatchingToolVersion();
152                    }
153    
154                    return _patchingToolVersionDisplayName;
155            }
156    
157            @Override
158            public String[] getPatchLevels() {
159                    if (_patchLevels != null) {
160                            return _patchLevels;
161                    }
162    
163                    Properties properties = getProperties();
164    
165                    _patchLevels = StringUtil.split(
166                            properties.getProperty(PROPERTY_PATCH_LEVELS));
167    
168                    return _patchLevels;
169            }
170    
171            @Override
172            public Properties getProperties() {
173                    if (_properties != null) {
174                            return _properties;
175                    }
176    
177                    return _getProperties(PATCHER_PROPERTIES);
178            }
179    
180            @Override
181            public boolean hasInconsistentPatchLevels() {
182                    return _inconsistentPatchLevels;
183            }
184    
185            @Override
186            public boolean isConfigured() {
187                    return _configured;
188            }
189    
190            @Override
191            public void verifyPatchLevels() throws PatchInconsistencyException {
192                    Properties portalImplJARProperties = _getProperties(PATCHER_PROPERTIES);
193    
194                    String[] portalImplJARPatches = _getInstalledPatches(
195                            portalImplJARProperties);
196    
197                    Arrays.sort(portalImplJARPatches);
198    
199                    Properties portalServiceJARProperties = _getProperties(
200                            PATCHER_SERVICE_PROPERTIES);
201    
202                    String[] serviceJARPatches = _getInstalledPatches(
203                            portalServiceJARProperties);
204    
205                    Arrays.sort(serviceJARPatches);
206    
207                    if (!Arrays.equals(portalImplJARPatches, serviceJARPatches)) {
208                            _log.error("Inconsistent patch level detected");
209    
210                            if (_log.isWarnEnabled()) {
211                                    if (ArrayUtil.isEmpty(portalImplJARPatches)) {
212                                            _log.warn(
213                                                    "There are no patches installed on portal-impl.jar");
214                                    }
215                                    else {
216                                            _log.warn(
217                                                    "Patch level on portal-impl.jar: " +
218                                                            Arrays.toString(portalImplJARPatches));
219                                    }
220    
221                                    if (ArrayUtil.isEmpty(serviceJARPatches)) {
222                                            _log.warn(
223                                                    "There are no patches installed on portal-kernel.jar");
224                                    }
225                                    else {
226                                            _log.warn(
227                                                    "Patch level on portal-kernel.jar: " +
228                                                            Arrays.toString(serviceJARPatches));
229                                    }
230                            }
231    
232                            _inconsistentPatchLevels = true;
233    
234                            throw new PatchInconsistencyException();
235                    }
236            }
237    
238            private String[] _getInstalledPatches(Properties properties) {
239                    if (properties == null) {
240                            properties = getProperties();
241                    }
242    
243                    _installedPatchNames = StringUtil.split(
244                            properties.getProperty(PROPERTY_INSTALLED_PATCHES));
245    
246                    return _installedPatchNames;
247            }
248    
249            private Properties _getProperties(String fileName) {
250                    if (Validator.isNull(fileName)) {
251                            fileName = PATCHER_PROPERTIES;
252                    }
253    
254                    Properties properties = new Properties();
255    
256                    Class<?> clazz = getClass();
257    
258                    if (Objects.equals(fileName, PATCHER_SERVICE_PROPERTIES)) {
259                            clazz = clazz.getInterfaces()[0];
260                    }
261    
262                    ClassLoader classLoader = clazz.getClassLoader();
263    
264                    InputStream inputStream = classLoader.getResourceAsStream(fileName);
265    
266                    if (inputStream == null) {
267                            if (_log.isDebugEnabled()) {
268                                    _log.debug("Unable to load " + fileName);
269                            }
270                    }
271                    else {
272                            try {
273                                    properties.load(inputStream);
274    
275                                    _configured = true;
276                            }
277                            catch (IOException ioe) {
278                                    _log.error(ioe, ioe);
279                            }
280                            finally {
281                                    StreamUtil.cleanUp(inputStream);
282                            }
283                    }
284    
285                    _properties = properties;
286    
287                    return _properties;
288            }
289    
290            private static final Log _log = LogFactoryUtil.getLog(PatcherImpl.class);
291    
292            private boolean _configured;
293            private String[] _fixedIssueKeys;
294            private boolean _inconsistentPatchLevels;
295            private String[] _installedPatchNames;
296            private File _patchDirectory;
297            private int _patchingToolVersion;
298            private String _patchingToolVersionDisplayName;
299            private String[] _patchLevels;
300            private Properties _properties;
301    
302    }