/* ====================================================================
*
* The ObjectStyle Group Software License, Version 1.0
*
* Copyright (c) 2002 - 2006 The ObjectStyle Group
* and individual authors of the software. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* ObjectStyle Group (http://objectstyle.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "ObjectStyle Group" and "Cayenne"
* must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact andrus@objectstyle.org.
*
* 5. Products derived from this software may not be called "ObjectStyle"
* nor may "ObjectStyle" appear in their names without prior written
* permission of the ObjectStyle Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the ObjectStyle Group. For more
* information on the ObjectStyle Group, please see
* <http://objectstyle.org/>.
*
*/
package org.objectstyle.woproject.ant;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Mapper;
import org.apache.tools.ant.types.selectors.SelectorUtils;
import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.IdentityMapper;
/**
* Mapper that handles WebObjects resource copying. It handles issues like
* localization, flattening of WOComponents paths, etc.
*
* @author Andrei Adamchik
*/
public class WOMapper extends Mapper {
private final String LPROJ_SUFFIX = ".lproj";
private final String SUBPROJ_SUFFIX = ".subproj";
private final String NON_LOCALIZED = "Nonlocalized" + LPROJ_SUFFIX;
WOTask wotask;
String[] pattern;
/**
* @param project
* @param parent
* The default constructor.
*/
public WOMapper(Project project, Task parent) {
super(project);
if (parent != null && parent instanceof WOTask) {
wotask = (WOTask) parent;
}
}
@Override
public FileNameMapper getImplementation() throws BuildException {
return new WOFileNameMapper();
}
class WOFileNameMapper extends IdentityMapper {
/**
* Returns an one-element array containing the source file name with a
* path rewritten using localization rules.
*/
@Override
public String[] mapFileName(String sourceFileName) {
// check for default exclusions
if (NON_LOCALIZED.equals(sourceFileName)) {
return null;
}
// apply filters
String subprojPath = subprojFilter(sourceFileName);
String localizedPath = localizationFilter(subprojPath);
String wocompPath = wocompFilter(localizedPath);
String resourcesPath = resourcesFilter(wocompPath);
String webserverresourcesPath = webserverResourcesFilter(resourcesPath);
String miscFilter = miscFilter(webserverresourcesPath);
String flattenfilesFilter = applyFlattenfiles(miscFilter);
String finalPath = eomodelFilter(flattenfilesFilter);
// System.out.println("mapFileName: " + sourceFileName + "->"+ finalPath);
return new String[] { finalPath };
}
/**
* Returns destination path based on source file path applying Resources
* rules to <code>path</code> if applicable.
*/
private final String resourcesFilter(String path) {
File f = new File(path);
// File in Resources directory
String parent = f.getParent();
if (parent != null && parent.equals("Resources")) {
return flatten(f);
}
// AK Wonder hack: we use WebServerResources as the base directory
String resourcesPattern = "Resources" + File.separator;
int index = path.indexOf(resourcesPattern);
if(index >= 0) {
return path.substring(index + resourcesPattern.length());
}
// skip the filter
return path;
}
/**
* Returns destination path based on source file path applying Resources
* rules to <code>path</code> if applicable.
*/
private final String webserverResourcesFilter(String path) {
File f = new File(path);
// File in Resources directory
String parent = f.getParent();
if (parent != null && parent.equals("WebServerResources")) {
return flatten(new File(path));
}
// AK Wonder hack: we use WebServerResources as the base directory
String webServerResourcesPattern = "WebServerResources" + File.separator;
int index = path.indexOf(webServerResourcesPattern);
if(index >= 0) {
return path.substring(index + webServerResourcesPattern.length());
}
// skip the filter
return path;
}
/**
* Returns destination path based on source file path applying
* miscancellous rules, like *.strings to <code>path</code> if
* applicable.
*/
private final String miscFilter(String path) {
File f = new File(path);
// add other file extensions here!
if (path.endsWith(".strings")) {
return flatten(f);
}
if (path.endsWith(".plist") && path.indexOf(".eomodeld") <= 0) {
return flatten(f);
}
// skip the filter
return path;
}
/**
* Returns destination path based on source file path applying
* WOComponent rules to <code>path</code> if applicable.
*/
private final String wocompFilter(String path) {
File f = new File(path);
// WOComponent directory or WOComponent's api
if (path.endsWith(".wo") || path.endsWith(".api")) {
return flatten(f);
}
// File in WOComponent directory
String parent = f.getParent();
if (parent != null && parent.endsWith(".wo")) {
return flattenWithParent(f);
}
// skip the filter
return path;
}
private final String eomodelFilter(String path) {
File f = new File(path);
// EOModel directory
if (path.endsWith(".eomodeld") && !path.endsWith("index.eomodeld")) {
return flatten(f);
}
// File in EOModel directory
String parent = f.getParent();
if (parent != null && parent.endsWith(".eomodeld")) {
return flattenWithParent(f);
}
// skip the filter
return path;
}
/**
* Returns destination path based on source file path applying subproj
* rules to <code>path</code>.
*/
private String subprojFilter(String path) {
File f = new File(path);
File p1 = f.getParentFile();
// check for localization
File p2 = null;
while (p1 != null) {
p2 = p1;
p1 = p1.getParentFile();
}
if (p2 != null) {
String topmostParent = p2.getName();
if (topmostParent.endsWith(SUBPROJ_SUFFIX))
return path.substring(topmostParent.length());
}
return path;
}
/**
* Returns destination path based on source file path applying
* localization rules to <code>path</code>.
*/
private String localizationFilter(String path) {
String result = path;
String localizationPattern = NON_LOCALIZED + File.separator;
int index = path.indexOf(localizationPattern);
if (index >= 0) {
result = path.substring(index + localizationPattern.length());
} else {
localizationPattern = LPROJ_SUFFIX + File.separator;
index = path.indexOf(localizationPattern);
if (index >= 0) {
result = path.replaceFirst(".*?(\\w+\\." + LPROJ_SUFFIX + ")", "$1");
}
}
return result;
}
/**
* Flatten path, taking localization into account. No need to check for
* Nonlocalized.lproj here, since it should've been stripped by
* localization filter already.
*/
private String flatten(File f) {
String result = null;
File p1 = f.getParentFile();
// check for localization
File p2 = null;
while (p1 != null) {
p2 = p1;
if(p1.getName().endsWith(LPROJ_SUFFIX)) {
break;
}
p1 = p1.getParentFile();
}
if (p2 != null) {
String topmostParent = p2.getName();
if (topmostParent.endsWith(LPROJ_SUFFIX)) {
result = topmostParent + File.separator + f.getName();
}
}
if(result == null) {
result = f.getName();
}
return result;
}
/*
* Pattern extracted from the Flattenfiles
*/
private String[] pattern() {
if (wotask != null) {
ArrayList<String> arrayList = new ArrayList<String>();
Iterator<String> iterator = wotask.getFlattenfileNames();
while (iterator.hasNext()) {
String fileName = (String) iterator.next();
addPattern(fileName, arrayList);
}
pattern = (String[]) arrayList.toArray(new String[arrayList.size()]);
}
return pattern;
}
private void addPattern(String fileName, ArrayList<String> arrayList) {
BufferedReader patternReader = null;
try {
patternReader = new BufferedReader(new FileReader(new File(fileName)));
String line = patternReader.readLine();
while (line != null) {
if (line.length() > 0) {
arrayList.add(line);
}
line = patternReader.readLine();
}
} catch (IOException ioe) {
WOMapper.this.log("Error while reading file: " + ioe.getMessage());
} finally {
if (null != patternReader) {
try {
patternReader.close();
} catch (IOException ioe) {
// Ignore exception
}
}
}
}
/*
* Apply Flattenfiles
*/
private String applyFlattenfiles(String path) {
if (pattern() == null)
return path;
File f = new File(path);
for (int i = 0; i < pattern.length; i++) {
if (SelectorUtils.matchPath(pattern[i], path)) {
return flatten(f);
}
}
// skip the filter
return path;
}
/**
* Flatten parent path, taking localization into account. No need to
* check for Nonlocalized.lproj here, since it should've been stripped
* by localization filter already.
*/
private String flattenWithParent(File f) {
String name = f.getName();
String parentName = flatten(f.getParentFile());
return parentName + File.separator + name;
}
}
}