001    /**
002     * Copyright (c) 2000-2013 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.lar.backgroundtask;
016    
017    import com.liferay.portal.NoSuchLayoutException;
018    import com.liferay.portal.RemoteExportException;
019    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskResult;
020    import com.liferay.portal.kernel.lar.MissingReferences;
021    import com.liferay.portal.kernel.util.FileUtil;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.MapUtil;
024    import com.liferay.portal.kernel.util.StreamUtil;
025    import com.liferay.portal.model.BackgroundTask;
026    import com.liferay.portal.model.Layout;
027    import com.liferay.portal.security.auth.HttpPrincipal;
028    import com.liferay.portal.service.LayoutLocalServiceUtil;
029    import com.liferay.portal.service.http.LayoutServiceHttp;
030    import com.liferay.portal.service.http.StagingServiceHttp;
031    import com.liferay.portal.util.PropsValues;
032    
033    import java.io.File;
034    import java.io.FileInputStream;
035    import java.io.Serializable;
036    
037    import java.util.ArrayList;
038    import java.util.Date;
039    import java.util.List;
040    import java.util.Map;
041    
042    /**
043     * @author Mate Thurzo
044     */
045    public class LayoutRemoteStagingBackgroundTaskExecutor
046            extends BaseStagingBackgroundTaskExecutor {
047    
048            @Override
049            public BackgroundTaskResult execute(BackgroundTask backgroundTask)
050                    throws Exception {
051    
052                    Map<String, Serializable> taskContextMap =
053                            backgroundTask.getTaskContextMap();
054    
055                    long sourceGroupId = MapUtil.getLong(taskContextMap, "groupId");
056                    boolean privateLayout = MapUtil.getBoolean(
057                            taskContextMap, "privateLayout");
058                    Map<Long, Boolean> layoutIdMap = (Map<Long, Boolean>)taskContextMap.get(
059                            "layoutIdMap");
060                    Map<String, String[]> parameterMap =
061                            (Map<String, String[]>)taskContextMap.get("parameterMap");
062                    long remoteGroupId = MapUtil.getLong(taskContextMap, "remoteGroupId");
063                    Date startDate = (Date)taskContextMap.get("startDate");
064                    Date endDate = (Date)taskContextMap.get("endDate");
065                    HttpPrincipal httpPrincipal = (HttpPrincipal)taskContextMap.get(
066                            "httpPrincipal");
067    
068                    clearBackgroundTaskStatus(backgroundTask);
069    
070                    long stagingRequestId = 0;
071    
072                    File file = null;
073                    FileInputStream fileInputStream = null;
074                    MissingReferences missingReferences = null;
075    
076                    try {
077                            file = exportLayoutsAsFile(
078                                    sourceGroupId, privateLayout, layoutIdMap, parameterMap,
079                                    remoteGroupId, startDate, endDate, httpPrincipal);
080    
081                            String checksum = FileUtil.getMD5Checksum(file);
082    
083                            fileInputStream = new FileInputStream(file);
084    
085                            stagingRequestId = StagingServiceHttp.createStagingRequest(
086                                    httpPrincipal, remoteGroupId, checksum);
087    
088                            byte[] bytes =
089                                    new byte[PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE];
090    
091                            int i = 0;
092    
093                            while ((i = fileInputStream.read(bytes)) >= 0) {
094                                    if (i < PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE) {
095                                            byte[] tempBytes = new byte[i];
096    
097                                            System.arraycopy(bytes, 0, tempBytes, 0, i);
098    
099                                            StagingServiceHttp.updateStagingRequest(
100                                                    httpPrincipal, stagingRequestId, file.getName(),
101                                                    tempBytes);
102                                    }
103                                    else {
104                                            StagingServiceHttp.updateStagingRequest(
105                                                    httpPrincipal, stagingRequestId, file.getName(), bytes);
106                                    }
107    
108                                    bytes =
109                                            new byte[PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE];
110                            }
111    
112                            missingReferences = StagingServiceHttp.validateStagingRequest(
113                                    httpPrincipal, stagingRequestId, privateLayout, parameterMap);
114    
115                            backgroundTask = markValidatedBackgroundTask(backgroundTask);
116    
117                            StagingServiceHttp.publishStagingRequest(
118                                    httpPrincipal, stagingRequestId, privateLayout, parameterMap);
119                    }
120                    finally {
121                            StreamUtil.cleanUp(fileInputStream);
122    
123                            FileUtil.delete(file);
124    
125                            if (stagingRequestId > 0) {
126                                    StagingServiceHttp.cleanUpStagingRequest(
127                                            httpPrincipal, stagingRequestId);
128                            }
129                    }
130    
131                    return processMissingReferences(backgroundTask, missingReferences);
132            }
133    
134            protected File exportLayoutsAsFile(
135                            long sourceGroupId, boolean privateLayout,
136                            Map<Long, Boolean> layoutIdMap, Map<String, String[]> parameterMap,
137                            long remoteGroupId, Date startDate, Date endDate,
138                            HttpPrincipal httpPrincipal)
139                    throws Exception {
140    
141                    if ((layoutIdMap == null) || layoutIdMap.isEmpty()) {
142                            return LayoutLocalServiceUtil.exportLayoutsAsFile(
143                                    sourceGroupId, privateLayout, null, parameterMap, startDate,
144                                    endDate);
145                    }
146                    else {
147                            List<Layout> layouts = new ArrayList<Layout>();
148    
149                            for (Map.Entry<Long, Boolean> entry : layoutIdMap.entrySet()) {
150                                    long plid = GetterUtil.getLong(String.valueOf(entry.getKey()));
151                                    boolean includeChildren = entry.getValue();
152    
153                                    Layout layout = LayoutLocalServiceUtil.getLayout(plid);
154    
155                                    if (!layouts.contains(layout)) {
156                                            layouts.add(layout);
157                                    }
158    
159                                    List<Layout> parentLayouts = getMissingRemoteParentLayouts(
160                                            httpPrincipal, layout, remoteGroupId);
161    
162                                    for (Layout parentLayout : parentLayouts) {
163                                            if (!layouts.contains(parentLayout)) {
164                                                    layouts.add(parentLayout);
165                                            }
166                                    }
167    
168                                    if (includeChildren) {
169                                            for (Layout childLayout : layout.getAllChildren()) {
170                                                    if (!layouts.contains(childLayout)) {
171                                                            layouts.add(childLayout);
172                                                    }
173                                            }
174                                    }
175                            }
176    
177                            long[] layoutIds = getLayoutIds(layouts);
178    
179                            if (layoutIds.length <= 0) {
180                                    throw new RemoteExportException(
181                                            RemoteExportException.NO_LAYOUTS);
182                            }
183    
184                            return LayoutLocalServiceUtil.exportLayoutsAsFile(
185                                    sourceGroupId, privateLayout, layoutIds, parameterMap,
186                                    startDate, endDate);
187                    }
188            }
189    
190            protected long[] getLayoutIds(List<Layout> layouts) {
191                    long[] layoutIds = new long[layouts.size()];
192    
193                    for (int i = 0; i < layouts.size(); i++) {
194                            Layout layout = layouts.get(i);
195    
196                            layoutIds[i] = layout.getLayoutId();
197                    }
198    
199                    return layoutIds;
200            }
201    
202            /**
203             * @see com.liferay.portal.staging.StagingImpl#getMissingParentLayouts(
204             *      Layout, long)
205             */
206            protected List<Layout> getMissingRemoteParentLayouts(
207                            HttpPrincipal httpPrincipal, Layout layout, long remoteGroupId)
208                    throws Exception {
209    
210                    List<Layout> missingRemoteParentLayouts = new ArrayList<Layout>();
211    
212                    long parentLayoutId = layout.getParentLayoutId();
213    
214                    while (parentLayoutId > 0) {
215                            Layout parentLayout = LayoutLocalServiceUtil.getLayout(
216                                    layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
217    
218                            try {
219                                    LayoutServiceHttp.getLayoutByUuidAndGroupId(
220                                            httpPrincipal, parentLayout.getUuid(), remoteGroupId,
221                                            parentLayout.getPrivateLayout());
222    
223                                    // If one parent is found all others are assumed to exist
224    
225                                    break;
226                            }
227                            catch (NoSuchLayoutException nsle) {
228                                    missingRemoteParentLayouts.add(parentLayout);
229    
230                                    parentLayoutId = parentLayout.getParentLayoutId();
231                            }
232                    }
233    
234                    return missingRemoteParentLayouts;
235            }
236    
237    }