View Javadoc

1   /*
2    * Copyright 2004-2006 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.tuigwaa.system;
17  
18  import java.io.ByteArrayInputStream;
19  import java.io.ByteArrayOutputStream;
20  import java.io.File;
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Date;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.zip.ZipEntry;
27  import java.util.zip.ZipInputStream;
28  import java.util.zip.ZipOutputStream;
29  
30  import org.apache.commons.io.FileUtils;
31  import org.apache.commons.io.IOUtils;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.seasar.tuigwaa.cms.ContentsStoreService;
35  import org.seasar.tuigwaa.cms.core.Resource;
36  import org.seasar.tuigwaa.util.MimeMappings;
37  import org.seasar.tuigwaa.util.TgwUtils;
38  
39  import com.isenshi.util.PathUtils;
40  import com.isenshi.util.ResourceUtils;
41  
42  /***
43   * @author someda
44   */
45  public class DesignServiceImpl implements DesignService {
46  	
47  	private static final String SKIN_TEMPLATE_DIR = "template/skin";
48  	private static final String SKIN_DIR = ".SKINS";
49  	
50  	private static final String SYSTEM_SKINPAGE_NAME = "page.html";	
51  	private static final String[] SYSTEM_AVAILABLE_PAGES = {SYSTEM_SKINPAGE_NAME};
52  		
53  	private ContentsStoreService storeService;
54  	
55  	private Log log = LogFactory.getLog(getClass());
56  	
57  	public DesignServiceImpl(ContentsStoreService storeService){
58  		this.storeService = storeService;		
59  	}
60  	
61  	public void init(){
62  		File skinTemplateDir = ResourceUtils.getFile(SKIN_TEMPLATE_DIR);		
63  		Resource resource = null;				
64  		try{
65  			resource=storeService.getResource(SKIN_DIR,SYSTEM_SKIN_NAME);
66  		}catch(TgwSecurityException tse){
67  			// should not be occurred, because this methods run by admin user
68  		}
69  		
70  		boolean copyFlag = false;		
71  		if(resource != null){
72  			Date lastModifiedDate = resource.getModificationDateAsDate();						
73  			File[] templates = skinTemplateDir.listFiles();
74  			for(int i=0;i<templates.length;i++){			
75  				if(SYSTEM_SKIN_NAME.equals(templates[i].getName())){				
76  					if(FileUtils.isFileNewer(templates[i],lastModifiedDate)){
77  						copyFlag = true;
78  					}
79  					break;
80  				}
81  			}
82  		}else{
83  			copyFlag = true;
84  		}
85  		
86  		if(copyFlag){
87  			log.warn("skin template resources are newer than WEB-DAV ones, starting to copy.");
88  			try {
89  				storeService.copyFromFileSystem(skinTemplateDir, SKIN_DIR);
90  			} catch (Exception e) {
91  				e.printStackTrace();
92  			}
93  		}
94  	}
95  			
96  	public String[] getAllSkinNames() {
97  		String skinNames[] = null;
98  		try {
99  			List list = storeService.getFolderList(SKIN_DIR, "");			
100 			skinNames = new String[list.size()];
101 			Iterator itr = list.iterator();
102 			for (int i = 0; itr.hasNext(); i++) {
103 				Resource resource = (Resource) itr.next();
104 				if(resource.isFolder()){
105 					// need-to-validate 
106 					skinNames[i] = resource.getPageName();					
107 				}
108 			}
109 		} catch (Exception e) {
110 			log.error("failed to load skin names : " + e.getMessage());
111 		}		
112 		return skinNames;		
113 	}
114 	
115 	public String[] getAvailableSkinNames(String siteName) {
116 		return getAllSkinNames(); // tempolary
117 	}	
118 
119 	public void uploadSkin(String skinName, ZipInputStream zipInput) throws TgwServiceException {
120 
121 		boolean isValid = false;
122 		ByteArrayOutputStream baos = null;
123 		ByteArrayInputStream bais = null;
124 		
125 		try{			
126 			storeService.createFolder(SKIN_DIR,skinName);
127 			
128 			ZipEntry entry = null; 
129 			String root = null;
130 			while((entry = zipInput.getNextEntry())!= null){				
131 				String name = entry.getName();
132 				if(root == null || !"".equals(root)){
133 					root = PathUtils.getRootPath(name);
134 				}
135 				String relative = PathUtils.getRelativePath(root,name);
136 				String uri = skinName + "/" + relative;				
137 				if(entry.isDirectory()){
138 					storeService.createFolder(SKIN_DIR,uri);					
139 				}else{					
140 					baos = new ByteArrayOutputStream();
141 					int length = 0;
142 					int contentLength = 0;
143 					int bufsize = 1024;
144 					byte[] buf = new byte[bufsize];
145 					while(zipInput.available() > 0 && ((length = zipInput.read(buf,0,bufsize)) != -1)){
146 						baos.write(buf,0,length);
147 						contentLength += length;
148 					}					
149 					bais = new ByteArrayInputStream(baos.toByteArray());
150 					
151 					String extension = PathUtils.getExtension(uri);
152 					String contentType = MimeMappings.getContentType(extension);
153 					storeService.createResource(SKIN_DIR,uri,contentType,contentLength,bais);
154 					
155 					baos.close();
156 					bais.close();
157 				}				
158 			}						
159 			if(!(isValid = validate(skinName))){ // roll-back
160 				throw new TgwServiceException("invalid upload contents for skin : " + skinName);
161 			}			
162 		}catch(IOException ioe){
163 			log.error("failed to read input stream : " + ioe.getMessage());
164 		}catch(IllegalArgumentException iae){ // in-case Japanese name
165 			log.error("archive including file with Japanese name not allowed.");
166 			throw new TgwServiceException("archive including file with Japanese name not allowed.");
167 		}catch(Exception e){
168 			log.error(e.getMessage());
169 			throw new TgwServiceException(e);
170 		}finally{			
171 			IOUtils.closeQuietly(baos);
172 			IOUtils.closeQuietly(bais);			
173 			if(!isValid){
174 				log.error("invalid upload skin : " + skinName);
175 				storeService.delete(SKIN_DIR,skinName);
176 			}
177 		}
178 	}
179 	
180 	public void downloadSkin(String skinName, ZipOutputStream zipOutput) throws TgwServiceException {
181 		
182 		try{			
183 			List resourceList = storeService.getRecursivePageOrFolderList(SKIN_DIR,skinName);
184 			for(Iterator i=resourceList.iterator();i.hasNext();){
185 				Resource resource = (Resource) i.next();
186 				String path = resource.getPath();
187 				zipOutput.putNextEntry(new ZipEntry(path));				
188 				if(!resource.isFolder()){
189 					storeService.writeResource(SKIN_DIR,path,zipOutput);
190 				}							
191 			}
192 		}catch(IOException ioe){
193 			log.error("failed to write output stream : " + ioe.getMessage());
194 		}catch(Exception e){
195 			log.error(e.getMessage());
196 			throw new TgwServiceException(e);
197 		}		
198 	}	
199 
200 	public void deleteSkin(String skinName, List configList) throws TgwServiceException {
201 		
202 		if(SYSTEM_SKIN_NAME.equals(skinName)){
203 			throw new TgwServiceException("system default skins (" + skinName + ") cannot be deleted.");
204 		}
205 		
206 		for(Iterator i=configList.iterator();i.hasNext();){
207 			SiteConfig siteConfig = (SiteConfig) i.next();
208 			if(skinName.equals(siteConfig.getSkin())){
209 				throw new TgwServiceException("skin (" + skinName + ") being used for site : " + siteConfig.getName());
210 			}
211 		}		
212 		
213 		try{
214 			storeService.delete(SKIN_DIR,skinName);
215 		}catch(Exception e){
216 			throw new TgwServiceException(e);
217 		}
218 	}
219 
220 	public void sync(SiteConfig siteConfig, boolean overwrite) throws TgwServiceException {
221 		
222 		String siteName = siteConfig.getName();
223 		String skinName = siteConfig.getSkin();
224 
225 		String siteRootPath = TgwUtils.getTuigwaaActionServlet()
226 		.getServletConfig().getServletContext().getRealPath(siteName);		
227 		File siteRoot = new File(siteRootPath);
228 		
229 		if(!siteRoot.exists()){
230 			siteRoot.mkdir();
231 		}else if(!overwrite){
232 			try{
233 				FileUtils.cleanDirectory(siteRoot);
234 			}catch(IOException ioe){// do-nothing				
235 			}
236 		}
237 		
238 		try{
239 			if(skinName.equals(ARCHIVE_SKIN_NAME)){ // Archive Skin
240 				
241 			}else{ // Web-DAV skin, needs version check ?
242 				storeService.copyToFileSystem(SKIN_DIR,skinName,siteRoot);
243 			}
244 		}catch(Exception e){
245 			log.error("failed to sync resources : " + e.getMessage());
246 		}
247 	}
248 	
249 
250 	public boolean validate(String skinName){
251 		
252 		boolean flag = false;
253 		// skin contains page.html
254 		String uri = skinName + "/" + SYSTEM_SKINPAGE_NAME;
255 		try{
256 			flag = storeService.isExistResource(SKIN_DIR,uri,true);
257 		}catch(TgwSecurityException tse){
258 			// do-nothing
259 			tse.printStackTrace();
260 		}
261 		return flag;
262 	}
263 	
264 	public void saveConfig(DesignConfig designConfig) throws TgwServiceException{
265 		//FIXME: need to implements		
266 	}
267 	
268 	public DesignConfig getDesignConfig(String skinName){
269 		
270 		DesignConfig designConfig = new DesignConfig();
271 		designConfig.setName(skinName);
272 		
273 		try{
274 			List list = storeService.getPageList(SKIN_DIR,skinName);
275 			List availablePageList = new ArrayList();
276 			for(Iterator i=list.iterator();i.hasNext();){
277 				Resource resource = (Resource)i.next();				
278 				String pagePath = resource.getPageName();				
279 				if(resource.isFile() && pagePath.endsWith("html")){					
280 					availablePageList.add(resource.getPageName());						
281 				}
282 			}
283 			int size = availablePageList.size();			
284 			String[] availablePages;
285 			if(size == 0){
286 				availablePages = SYSTEM_AVAILABLE_PAGES;
287 			}else{
288 				availablePages = (String[])availablePageList.toArray(new String[size]);
289 			}			
290 			designConfig.setAvailablePages(availablePages);			
291 		}catch(Exception e){
292 			designConfig.setAvailablePages(SYSTEM_AVAILABLE_PAGES);
293 		}
294 						
295 		return designConfig;
296 	}
297 	// ----- [private methods ] -----
298 	
299 	
300 }