001/*
002 *  Copyright 2017 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.extraction.edition;
017
018import java.io.File;
019import java.io.IOException;
020import java.io.OutputStream;
021import java.nio.file.Files;
022import java.nio.file.Paths;
023import java.util.LinkedHashMap;
024import java.util.Map;
025import java.util.Properties;
026
027import javax.xml.transform.OutputKeys;
028import javax.xml.transform.TransformerFactory;
029import javax.xml.transform.sax.SAXTransformerFactory;
030import javax.xml.transform.sax.TransformerHandler;
031import javax.xml.transform.stream.StreamResult;
032
033import org.apache.avalon.framework.service.ServiceException;
034import org.apache.avalon.framework.service.ServiceManager;
035import org.apache.cocoon.xml.XMLUtils;
036import org.apache.excalibur.source.Source;
037import org.apache.excalibur.source.SourceResolver;
038import org.apache.excalibur.source.impl.FileSource;
039import org.apache.xml.serializer.OutputPropertiesFactory;
040
041import org.ametys.core.ui.Callable;
042import org.ametys.core.ui.StaticClientSideElement;
043import org.ametys.plugins.extraction.ExtractionConstants;
044
045/**
046 * This client site element manages a button to create an extraction definition file
047 */
048public class EditExtractionClientSideElement extends StaticClientSideElement
049{
050    /** The Avalon role name */
051    public static final String ROLE = EditExtractionClientSideElement.class.getName();
052    
053    private SourceResolver _sourceResolver;
054    
055    @Override
056    public void service(ServiceManager serviceManager) throws ServiceException
057    {
058        super.service(serviceManager);
059        _sourceResolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE);
060    }
061
062    /**
063     * Creates an extraction definition file.
064     * @param definitionFileName The extraction definition name
065     * @return Map containing success boolean and error codes if one occurs
066     * @throws Exception if an error occurs
067     */
068    @Callable (right = "Extraction_Rights_EditExtraction")
069    public Map<String, Object> createExtraction(String definitionFileName) throws Exception
070    {
071        Map<String, Object> response = new LinkedHashMap<>();
072        
073        // Create extraction definitions directory
074        Source definitionsSrc = _sourceResolver.resolveURI(ExtractionConstants.DEFINITIONS_DIR);
075        File definitionsDir = ((FileSource) definitionsSrc).getFile();
076        definitionsDir.mkdirs();
077        
078        String definitionFilePath = ExtractionConstants.DEFINITIONS_DIR + definitionFileName;
079        Source definitionSrc = _sourceResolver.resolveURI(definitionFilePath);
080        File definitionFile = ((FileSource) definitionSrc).getFile();
081
082        if (definitionFile.exists())
083        {
084            if (getLogger().isErrorEnabled())
085            {
086                getLogger().error("A definition file already exists with name '" + definitionFileName + "'");
087            }
088            response.put("success", false);
089            response.put("error", "already-exists");
090            return response;
091        }
092        
093        try (OutputStream os = Files.newOutputStream(Paths.get(definitionFile.getAbsolutePath())))
094        {
095            // Create a transformer for saving sax into a file
096            TransformerHandler handler = ((SAXTransformerFactory) TransformerFactory.newInstance()).newTransformerHandler();
097            
098            StreamResult result = new StreamResult(os);
099            handler.setResult(result);
100
101            // create the format of result
102            Properties format = new Properties();
103            format.put(OutputKeys.METHOD, "xml");
104            format.put(OutputKeys.INDENT, "yes");
105            format.put(OutputKeys.ENCODING, "UTF-8");
106            format.put(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "4");
107            handler.getTransformer().setOutputProperties(format);
108
109            // sax skeleton
110            handler.startDocument();
111            XMLUtils.createElement(handler, "extraction");
112            handler.endDocument();
113        }
114        catch (Exception e)
115        {
116            if (getLogger().isErrorEnabled())
117            {
118                getLogger().error("Error when trying to create the extraction definition file '" + definitionFileName + "'", e);
119            }
120            response.put("success", false);
121            response.put("error", "other-error");
122            return response;
123        }
124        
125        response.put("success", true);
126        return response;
127    }
128    
129    /**
130     * Renames an extraction definition file.
131     * @param definitionOldFileName The extraction definition old file name
132     * @param definitionNewFileName The extraction definition new file name
133     * @return Map containing success boolean and error codes if one occurs
134     * @throws Exception if an error occurs
135     */
136    @Callable (right = "Extraction_Rights_EditExtraction")
137    public Map<String, Object> renameExtraction(String definitionOldFileName, String definitionNewFileName) throws Exception
138    {
139        Map<String, Object> response = new LinkedHashMap<>();
140        
141        String oldFilePath = ExtractionConstants.DEFINITIONS_DIR + definitionOldFileName;
142        Source oldSrc = _sourceResolver.resolveURI(oldFilePath);
143        File oldFile = ((FileSource) oldSrc).getFile();
144        
145        if (!oldFile.exists())
146        {
147            if (getLogger().isErrorEnabled())
148            {
149                getLogger().error("Error while renaming '" + definitionOldFileName + "': this definition file doesn't exist.");
150            }
151            response.put("success", false);
152            response.put("error", "unexisting");
153            return response;
154        }
155        
156        String newFilePath = ExtractionConstants.DEFINITIONS_DIR + definitionNewFileName;
157        Source newSrc = _sourceResolver.resolveURI(newFilePath);
158        File newFile = ((FileSource) newSrc).getFile();
159        
160        if (newFile.exists())
161        {
162            if (getLogger().isErrorEnabled())
163            {
164                getLogger().error("Error while renaming to '" + definitionNewFileName + "': a definition file with this name already exists.");
165            }
166            response.put("success", false);
167            response.put("error", "already-exists");
168            return response;
169        }
170
171        // Copy old file in the new one
172        try
173        {
174            Files.copy(oldFile.toPath(), newFile.toPath());
175        }
176        catch (IOException e)
177        {
178            if (getLogger().isErrorEnabled())
179            {
180                getLogger().error("Error while copying old definition file '" + definitionOldFileName + "' in the new one.", e);
181            }
182            response.put("success", false);
183            response.put("error", "other-error");
184            return response;
185        }
186        
187        try
188        {
189            Files.deleteIfExists(oldFile.toPath());
190        }
191        catch (IOException e)
192        {
193            if (getLogger().isErrorEnabled())
194            {
195                getLogger().error("Error while deleting old definition file '" + definitionOldFileName + "'.", e);
196            }
197            response.put("success", false);
198            response.put("error", "other-error");
199            return response;
200        }
201        
202        response.put("success", true);
203        return response;
204    }
205    
206    /**
207     * Deletes an extraction definition file.
208     * @param definitionFileName The extraction definition file to delete
209     * @return <code>true</code> if extraction deletion succeed, <code>false</code> otherwise
210     * @throws Exception if an error occurs
211     */
212    @Callable (right = "Extraction_Rights_EditExtraction")
213    public boolean deleteExtraction(String definitionFileName) throws Exception
214    {
215        String filePath = ExtractionConstants.DEFINITIONS_DIR + definitionFileName;
216        Source source = _sourceResolver.resolveURI(filePath);
217        File file = ((FileSource) source).getFile();
218        
219        if (!file.exists())
220        {
221            throw new IllegalArgumentException("Error while deleting '" + definitionFileName + "': this definition file doesn't exist.");
222        }
223        
224        try
225        {
226            Files.deleteIfExists(file.toPath());
227        }
228        catch (IOException e)
229        {
230            if (getLogger().isErrorEnabled())
231            {
232                getLogger().error("Error while deleting definition file '" + definitionFileName + "'.", e);
233            }
234            throw e;
235        }
236        
237        return true;
238    }
239
240}