├── .gitignore ├── src └── main │ ├── resources │ └── template │ │ ├── seimi.cfg │ │ ├── run.bat │ │ └── run.sh │ └── java │ └── cn │ └── wanghaomiao │ └── maven │ └── plugin │ └── seimi │ ├── TemplateTask.java │ ├── WarInPlaceMojo.java │ ├── overlay │ ├── InvalidOverlayConfigurationException.java │ ├── DefaultOverlay.java │ └── OverlayManager.java │ ├── packaging │ ├── WarPackagingTask.java │ ├── WarPostPackagingTask.java │ ├── CopyUserManifestTask.java │ ├── SaveWebappStructurePostPackagingTask.java │ ├── ClassesPackagingTask.java │ ├── OverlayPackagingTask.java │ ├── WarPackagingContext.java │ ├── ArtifactsPackagingTask.java │ ├── DependenciesAnalysisPackagingTask.java │ ├── WarProjectPackagingTask.java │ └── AbstractWarPackagingTask.java │ ├── WarExplodedMojo.java │ ├── util │ ├── DependencyInfo.java │ ├── WebappStructureSerializer.java │ ├── ClassesPackager.java │ ├── WarUtils.java │ ├── PathSet.java │ └── WebappStructure.java │ ├── WarManifestMojo.java │ ├── Overlay.java │ └── SeimiMojo.java ├── readme.md ├── pom.xml └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | .idea 3 | *.iml 4 | target 5 | target/* 6 | *.class 7 | .classpath 8 | .project 9 | .settings/ -------------------------------------------------------------------------------- /src/main/resources/template/seimi.cfg: -------------------------------------------------------------------------------- 1 | [init_cfg] 2 | params=-c basic -p 8080 3 | 4 | [linux] 5 | stdout=/tmp/seimicrawler.stdout.log -------------------------------------------------------------------------------- /src/main/resources/template/run.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set JAVA_CMD=java 3 | set SEIMI_HOME=%cd% 4 | set CLASS_PATH=.;%SEIMI_HOME%\seimi\classes;%SEIMI_HOME%\seimi\lib\*; 5 | % windows环境下注意日志输出编码要与系统控制台一致 % 6 | set SEIMI_SYS_ARGS=-Dfile.encoding=GBK 7 | % e.g. -c 这里指定要启动的Crawler的name,-p 参数为数字,是启动该端口号的内置http服务接受http接口发送过来的Request % 8 | %JAVA_CMD% -cp %CLASS_PATH% %SEIMI_SYS_ARGS% cn.wanghaomiao.seimi.boot.Run -p %1 -c %2 -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/TemplateTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi; 2 | 3 | 4 | import org.apache.commons.io.FileUtils; 5 | import org.apache.commons.io.IOUtils; 6 | import org.apache.maven.plugin.logging.Log; 7 | 8 | import java.io.File; 9 | import java.net.URL; 10 | 11 | /** 12 | * @author github.com/zhegexiaohuozi [seimimaster@gmail.com] 13 | * @since 2015/12/28. 14 | */ 15 | public class TemplateTask { 16 | private File outDir; 17 | private Log log; 18 | 19 | public TemplateTask(File outDir, Log log) { 20 | this.outDir = outDir; 21 | this.log = log; 22 | } 23 | 24 | public void createBinFile() { 25 | try { 26 | File bin = new File(outDir, "bin"); 27 | bin.mkdir(); 28 | createFile(bin, "seimi.cfg"); 29 | createFile(bin, "run.bat"); 30 | createFile(bin, "run.sh"); 31 | 32 | } catch (Exception e) { 33 | log.error(e.getMessage(), e); 34 | } 35 | } 36 | 37 | public void createFile(File dir, String fileName) { 38 | try { 39 | URL resource = this.getClass().getClassLoader().getResource("template/" + fileName); 40 | assert resource != null; 41 | String content = IOUtils.toString(resource.openStream()); 42 | content = content.replaceAll("\r",""); 43 | FileUtils.writeStringToFile(new File(dir, fileName),content); 44 | } catch (Exception e) { 45 | log.error(e.getMessage(), e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/WarInPlaceMojo.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.plugin.MojoExecutionException; 23 | import org.apache.maven.plugin.MojoFailureException; 24 | import org.apache.maven.plugins.annotations.Mojo; 25 | import org.apache.maven.plugins.annotations.ResolutionScope; 26 | 27 | /** 28 | * Generate the webapp in the WAR source directory. 29 | * 30 | * @version $Id: WarInPlaceMojo.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 31 | */ 32 | @Mojo( name = "inplace", requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true ) 33 | public class WarInPlaceMojo 34 | extends AbstractWarMojo 35 | { 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | public void execute() 40 | throws MojoExecutionException, MojoFailureException 41 | { 42 | getLog().info( "Generating webapp in source directory [" + getWarSourceDirectory() + "]" ); 43 | 44 | buildExplodedWebapp( getWarSourceDirectory() ); 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/overlay/InvalidOverlayConfigurationException.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.overlay; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.plugin.MojoExecutionException; 23 | 24 | /** 25 | * Thrown if the overlay configuration is invalid. 26 | * 27 | * @author Stephane Nicoll 28 | * @version $Id: InvalidOverlayConfigurationException.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 29 | */ 30 | public class InvalidOverlayConfigurationException 31 | extends MojoExecutionException 32 | { 33 | 34 | /** 35 | * @param string Set the message of the exception. 36 | */ 37 | public InvalidOverlayConfigurationException( String string ) 38 | { 39 | super( string ); 40 | } 41 | 42 | /** 43 | * @param string Set the message of the exception. 44 | * @param throwable {@link Throwable} 45 | */ 46 | public InvalidOverlayConfigurationException( String string, Throwable throwable ) 47 | { 48 | super( string, throwable ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/WarPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.plugin.MojoExecutionException; 23 | import org.apache.maven.plugin.MojoFailureException; 24 | 25 | /** 26 | * The base packaging task. 27 | * 28 | * @author Stephane Nicoll 29 | * @version $Id: WarPackagingTask.java 1628849 2014-10-01 22:03:26Z khmarbaise $ 30 | */ 31 | public interface WarPackagingTask 32 | { 33 | 34 | /** 35 | * Performs the packaging for the specified task. 36 | *

37 | * The task is responsible to update the packaging context, namely with the files that have been copied. 38 | * 39 | * @param context the packaging context 40 | * @throws MojoExecutionException if an error occurred 41 | * @throws MojoFailureException if the project configuration is invalid 42 | */ 43 | void performPackaging( WarPackagingContext context ) 44 | throws MojoExecutionException, MojoFailureException; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/WarPostPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.plugin.MojoExecutionException; 23 | import org.apache.maven.plugin.MojoFailureException; 24 | 25 | /** 26 | * Defines tasks that should be performed after the packaging. 27 | * 28 | * @author Stephane Nicoll 29 | * @version $Id: WarPostPackagingTask.java 1628849 2014-10-01 22:03:26Z khmarbaise $ 30 | */ 31 | public interface WarPostPackagingTask 32 | { 33 | 34 | /** 35 | * Executes the post packaging task. 36 | *

37 | * The packaging context hold all information regarding the webapp that has been packaged. 38 | * 39 | * @param context the packaging context 40 | * @throws MojoExecutionException if an error occurred 41 | * @throws MojoFailureException if a failure occurred 42 | */ 43 | void performPostPackaging( WarPackagingContext context ) 44 | throws MojoExecutionException, MojoFailureException; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/WarExplodedMojo.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.plugin.MojoExecutionException; 23 | import org.apache.maven.plugin.MojoFailureException; 24 | import org.apache.maven.plugins.annotations.LifecyclePhase; 25 | import org.apache.maven.plugins.annotations.Mojo; 26 | import org.apache.maven.plugins.annotations.ResolutionScope; 27 | 28 | /** 29 | * Create an exploded webapp in a specified directory. 30 | * 31 | * @version $Id: WarExplodedMojo.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 32 | */ 33 | // CHECKSTYLE_OFF: LineLength 34 | @Mojo( name = "exploded", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true, requiresDependencyResolution = ResolutionScope.RUNTIME ) 35 | public class WarExplodedMojo 36 | extends AbstractWarMojo 37 | { 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | public void execute() 42 | throws MojoExecutionException, MojoFailureException 43 | { 44 | getLog().info( "Exploding webapp" ); 45 | 46 | buildExplodedWebapp( getWebappDirectory() ); 47 | } 48 | 49 | } 50 | // CHECKSTYLE_ON: LineLength 51 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/overlay/DefaultOverlay.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.overlay; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.artifact.Artifact; 23 | import cn.wanghaomiao.maven.plugin.seimi.Overlay; 24 | 25 | /** 26 | * A default overlay implementation based on an {@link Artifact}. 27 | * 28 | * @author Stephane Nicoll 29 | * @version $Id: DefaultOverlay.java 1628849 2014-10-01 22:03:26Z khmarbaise $ 30 | */ 31 | public class DefaultOverlay 32 | extends Overlay 33 | { 34 | 35 | /** 36 | * Creates an overlay for the specified artifact. 37 | * 38 | * @param a the artifact 39 | */ 40 | public DefaultOverlay( Artifact a ) 41 | { 42 | super(); 43 | setGroupId( a.getGroupId() ); 44 | setArtifactId( a.getArtifactId() ); 45 | setClassifier( a.getClassifier() ); 46 | setArtifact( a ); 47 | setType( a.getType() ); 48 | } 49 | 50 | /** 51 | * Creates an overlay for the specified artifact. 52 | * 53 | * @param a the artifact 54 | * @param includes the includes to use 55 | * @param excludes the excludes to use 56 | */ 57 | public DefaultOverlay( Artifact a, String includes, String excludes ) 58 | { 59 | this( a ); 60 | setIncludes( includes ); 61 | setExcludes( excludes ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/CopyUserManifestTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | 25 | import org.apache.maven.plugin.MojoExecutionException; 26 | import org.apache.maven.plugin.MojoFailureException; 27 | import org.apache.maven.plugin.logging.Log; 28 | import org.apache.maven.plugin.logging.SystemStreamLog; 29 | 30 | /** 31 | * @author Haikal Saadh 32 | * 33 | */ 34 | public class CopyUserManifestTask 35 | extends AbstractWarPackagingTask 36 | { 37 | 38 | /** Instance logger */ 39 | private Log log; 40 | 41 | public Log getLog() 42 | { 43 | if ( log == null ) 44 | { 45 | log = new SystemStreamLog(); 46 | } 47 | return log; 48 | } 49 | 50 | public void setLog( Log log ) 51 | { 52 | this.log = log; 53 | } 54 | 55 | public void performPackaging( WarPackagingContext context ) 56 | throws MojoExecutionException, MojoFailureException 57 | { 58 | File userManifest = context.getArchive().getManifestFile(); 59 | if ( userManifest != null ) 60 | { 61 | 62 | try 63 | { 64 | getLog().info( "Copying manifest..." ); 65 | File metainfDir = new File( context.getWebappDirectory(), META_INF_PATH ); 66 | copyFile( context, userManifest, new File( metainfDir, "MANIFEST.MF" ), "META-INF/MANIFEST.MF", true ); 67 | 68 | } 69 | catch ( IOException e ) 70 | { 71 | throw new MojoExecutionException( "Error copying user manifest", e ); 72 | } 73 | } 74 | 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | maven-seimicrawler-plugin 2 | ========== 3 | Package seimicrawler project so that can be fast and standalone deployed.It is based on maven-war-plugin and modified. 4 | 5 | `maven-seimicrawler-plugin`是基于`maven-war-plugin` v2.6版本修改定制而来。旨在方便开发者对于SeimiCrawler工程的快速打包并独立部署。 6 | 7 | # 开始 # 8 | pom添加添加plugin 9 | ``` 10 | 11 | cn.wanghaomiao 12 | maven-seimicrawler-plugin 13 | 1.3.0 14 | 15 | 16 | package 17 | 18 | build 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ``` 28 | 执行`mvn clean package`即可,包目录结构如下: 29 | ``` 30 | . 31 | ├── bin # 相应的脚本中也有具体启动参数说明介绍,在此不再敖述 32 | │ ├── run.bat # windows下启动脚本 33 | │ └── run.sh # Linux下启动脚本 34 | │ └── seimi.cfg # Linux下启动配置 35 | └── seimi 36 | ├── classes # Crawler工程业务类及相关配置文件目录 37 | └── lib # 工程依赖包目录 38 | ``` 39 | 40 | ## 启动说明 ## 41 | 42 | ### Linux ### 43 | 44 | #### 启动说明 #### 45 | ``` 46 | SeimiCrawler service helper 47 | usage: run.sh [options] 48 | start start service 49 | stop stop service 50 | help Print service help 51 | ``` 52 | 53 | - `./bin/run.sh start` 54 | 启动seimicrawler服务 55 | 56 | - `./bin/run.sh stop` 57 | 停止当前seimicrawler服务 58 | 59 | - `./bin/run.sh help` 60 | 查看使用说明 61 | 62 | #### 配置文件 #### 63 | 64 | ``` 65 | [init_cfg] 66 | params=-c basic -p 8080 67 | 68 | [linux] 69 | stdout=/tmp/seimicrawler.stdout.log 70 | ``` 71 | `params`只启动seimicrawler时启动参数,其中`-p`指定端口启动一个内嵌的http服务,接受通过http接口(参考SeimiCrawler文档有说明具体的接口)添加抓取请求或是查询抓取状态等操作,`-c`指定要启动的crawler的名称,如果不指定,默认是以workers形式启动所有扫描到的crawler,并开始监听抓取请求。两个参数都不是必须的。`stdout`配置的是seimicrawler服务启动后控制台日志输出路径。 72 | 73 | ### windows ### 74 | 75 | windows脚本比较简单,全部内容都在`run.bat`里了,直接在里面改就好了。 76 | 77 | # SeimiCrawler项目 # 78 | SeimiCrawler是一个敏捷的,独立部署的,支持分布式的Java爬虫框架,希望能在最大程度上降低新手开发一个可用性高且性能不差的爬虫系统的门槛,以及提升开发爬虫系统的开发效率。在SeimiCrawler的世界里,绝大多数人只需关心去写抓取的业务逻辑就够了,其余的Seimi帮你搞定。设计思想上SeimiCrawler受Python的爬虫框架Scrapy启发很大,同时融合了Java语言本身特点与Spring的特性,并希望在国内更方便且普遍的使用更有效率的XPath解析HTML,所以SeimiCrawler默认的HTML解析器是[JsoupXpath](http://jsoupxpath.wanghaomiao.cn)(独立扩展项目,非jsoup自带),默认解析提取HTML数据工作均使用XPath来完成(当然,数据处理亦可以自行选择其他解析器)。 79 | 80 | > 直达[SeimiCrawler](https://github.com/zhegexiaohuozi/SeimiCrawler)项目 81 | 82 | # 社区讨论 # 83 | 大家有什么问题或建议现在都可以选择通过下面的邮件列表讨论,首次发言前需先订阅并等待审核通过(主要用来屏蔽广告宣传等) 84 | - 订阅:请发邮件到 `seimicrawler+subscribe@googlegroups.com` 85 | - 发言:请发邮件到 `seimicrawler@googlegroups.com` 86 | - 退订:请发邮件至 `seimicrawler+unsubscribe@googlegroups.com` -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/SaveWebappStructurePostPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import cn.wanghaomiao.maven.plugin.seimi.util.WebappStructureSerializer; 23 | import org.apache.maven.plugin.MojoExecutionException; 24 | import org.apache.maven.plugin.MojoFailureException; 25 | 26 | import java.io.File; 27 | import java.io.IOException; 28 | 29 | /** 30 | * Saves the webapp structure cache. 31 | * 32 | * @author Stephane Nicoll 33 | * @version $Id: SaveWebappStructurePostPackagingTask.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 34 | */ 35 | public class SaveWebappStructurePostPackagingTask 36 | implements WarPostPackagingTask 37 | { 38 | 39 | private final File targetFile; 40 | 41 | private final WebappStructureSerializer serialier; 42 | 43 | /** 44 | * @param targetFile {@link #targetFile} 45 | */ 46 | public SaveWebappStructurePostPackagingTask( File targetFile ) 47 | { 48 | this.targetFile = targetFile; 49 | this.serialier = new WebappStructureSerializer(); 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | public void performPostPackaging( WarPackagingContext context ) 56 | throws MojoExecutionException, MojoFailureException 57 | { 58 | if ( targetFile == null ) 59 | { 60 | context.getLog().debug( "Cache usage is disabled, not saving webapp structure." ); 61 | } 62 | else 63 | { 64 | try 65 | { 66 | serialier.toXml( context.getWebappStructure(), targetFile ); 67 | context.getLog().debug( "Cache saved successfully." ); 68 | } 69 | catch ( IOException e ) 70 | { 71 | throw new MojoExecutionException( "Could not save webapp structure", e ); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/util/DependencyInfo.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.util; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.model.Dependency; 23 | 24 | /** 25 | * Holds a dependency and packaging information. 26 | * 27 | * @author Stephane Nicoll 28 | * @version $Id: DependencyInfo.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 29 | */ 30 | public class DependencyInfo 31 | { 32 | 33 | private final Dependency dependency; 34 | 35 | private String targetFileName; 36 | 37 | /** 38 | * Creates a new instance. 39 | * 40 | * @param dependency the dependency 41 | */ 42 | public DependencyInfo( Dependency dependency ) 43 | { 44 | this.dependency = dependency; 45 | } 46 | 47 | /** 48 | * Returns the dependency. 49 | * 50 | * @return the dependency 51 | */ 52 | public Dependency getDependency() 53 | { 54 | return dependency; 55 | } 56 | 57 | /** 58 | * Returns the target filen ame of the dependency. If no target file name is associated, returns null. 59 | * 60 | * @return the target file name or null 61 | */ 62 | public String getTargetFileName() 63 | { 64 | return targetFileName; 65 | } 66 | 67 | /** 68 | * Sets the target file name. 69 | * 70 | * @param targetFileName the target file name 71 | */ 72 | public void setTargetFileName( String targetFileName ) 73 | { 74 | this.targetFileName = targetFileName; 75 | } 76 | 77 | /** 78 | * {@inheritDoc} 79 | */ 80 | public boolean equals( Object o ) 81 | { 82 | if ( this == o ) 83 | { 84 | return true; 85 | } 86 | if ( o == null || getClass() != o.getClass() ) 87 | { 88 | return false; 89 | } 90 | 91 | DependencyInfo that = (DependencyInfo) o; 92 | 93 | if ( dependency != null ? !dependency.equals( that.dependency ) : that.dependency != null ) 94 | { 95 | return false; 96 | } 97 | 98 | return true; 99 | } 100 | 101 | /** 102 | * {@inheritDoc} 103 | */ 104 | public int hashCode() 105 | { 106 | int result; 107 | result = ( dependency != null ? dependency.hashCode() : 0 ); 108 | result = 31 * result + ( targetFileName != null ? targetFileName.hashCode() : 0 ); 109 | return result; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/WarManifestMojo.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.archiver.MavenArchiver; 23 | import org.apache.maven.artifact.DependencyResolutionRequiredException; 24 | import org.apache.maven.plugin.MojoExecutionException; 25 | import org.apache.maven.plugins.annotations.Component; 26 | import org.apache.maven.plugins.annotations.LifecyclePhase; 27 | import org.apache.maven.plugins.annotations.Mojo; 28 | import org.apache.maven.plugins.annotations.ResolutionScope; 29 | import org.codehaus.plexus.archiver.Archiver; 30 | import org.codehaus.plexus.archiver.jar.Manifest; 31 | import org.codehaus.plexus.archiver.jar.ManifestException; 32 | import org.codehaus.plexus.archiver.war.WarArchiver; 33 | import org.codehaus.plexus.util.IOUtil; 34 | import org.codehaus.plexus.util.WriterFactory; 35 | 36 | import java.io.File; 37 | import java.io.IOException; 38 | import java.io.PrintWriter; 39 | 40 | /** 41 | * Generate a manifest for this webapp. The manifest file is created in the warSourceDirectory. 42 | * 43 | * @author Mike Perham 44 | * @version $Id: WarManifestMojo.java 1636820 2014-11-05 08:27:25Z khmarbaise $ 45 | */ 46 | // CHECKSTYLE_OFF: LineLength 47 | @Mojo( name = "manifest", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, threadSafe = true, requiresDependencyResolution = ResolutionScope.RUNTIME ) 48 | // CHECKSTYLE_ON: LineLength 49 | public class WarManifestMojo 50 | extends AbstractWarMojo 51 | { 52 | /** 53 | * The WAR archiver. 54 | */ 55 | @Component( role = Archiver.class, hint = "war" ) 56 | private WarArchiver warArchiver; 57 | 58 | /** 59 | * Executes this mojo on the current project. 60 | * 61 | * @throws MojoExecutionException if an error occurred while building the webapp 62 | */ 63 | public void execute() 64 | throws MojoExecutionException 65 | { 66 | File manifestDir = new File( getWarSourceDirectory(), "META-INF" ); 67 | if ( !manifestDir.exists() ) 68 | { 69 | manifestDir.mkdirs(); 70 | } 71 | File manifestFile = new File( manifestDir, "MANIFEST.MF" ); 72 | MavenArchiver ma = new MavenArchiver(); 73 | ma.setArchiver( warArchiver ); 74 | ma.setOutputFile( manifestFile ); 75 | 76 | PrintWriter printWriter = null; 77 | try 78 | { 79 | Manifest mf = ma.getManifest( getSession(), getProject(), getArchive() ); 80 | printWriter = new PrintWriter( WriterFactory.newWriter( manifestFile, WriterFactory.UTF_8 ) ); 81 | mf.write( printWriter ); 82 | } 83 | catch ( ManifestException e ) 84 | { 85 | throw new MojoExecutionException( "Error preparing the manifest: " + e.getMessage(), e ); 86 | } 87 | catch ( DependencyResolutionRequiredException e ) 88 | { 89 | throw new MojoExecutionException( "Error preparing the manifest: " + e.getMessage(), e ); 90 | } 91 | catch ( IOException e ) 92 | { 93 | throw new MojoExecutionException( "Error preparing the manifest: " + e.getMessage(), e ); 94 | } 95 | finally 96 | { 97 | IOUtil.close( printWriter ); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/util/WebappStructureSerializer.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.util; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import com.thoughtworks.xstream.XStream; 23 | import com.thoughtworks.xstream.io.xml.DomDriver; 24 | import org.apache.maven.model.Dependency; 25 | import org.codehaus.plexus.util.IOUtil; 26 | import org.codehaus.plexus.util.ReaderFactory; 27 | import org.codehaus.plexus.util.WriterFactory; 28 | 29 | import java.io.File; 30 | import java.io.IOException; 31 | import java.io.Reader; 32 | import java.io.Writer; 33 | 34 | /** 35 | * Serializes {@link WebappStructure} back and forth. 36 | * 37 | * @author Stephane Nicoll 38 | * @version $Id: WebappStructureSerializer.java 1636820 2014-11-05 08:27:25Z khmarbaise $ 39 | */ 40 | public class WebappStructureSerializer 41 | { 42 | 43 | private static final XStream XSTREAM; 44 | 45 | static 46 | { 47 | XSTREAM = new XStream( new DomDriver() ); 48 | 49 | // Register aliases 50 | XSTREAM.alias( "webapp-structure", WebappStructure.class ); 51 | XSTREAM.alias( "path-set", PathSet.class ); 52 | XSTREAM.alias( "dependency", Dependency.class ); 53 | 54 | } 55 | 56 | /** 57 | * Creates a new instance of the serializer. 58 | */ 59 | public WebappStructureSerializer() 60 | { 61 | } 62 | 63 | /** 64 | * Reads the {@link WebappStructure} from the specified file. 65 | * 66 | * @param file the file containing the webapp structure 67 | * @return the webapp structure 68 | * @throws IOException if an error occurred while reading the structure 69 | */ 70 | public WebappStructure fromXml( File file ) 71 | throws IOException 72 | { 73 | Reader reader = null; 74 | 75 | try 76 | { 77 | reader = ReaderFactory.newXmlReader( file ); 78 | return (WebappStructure) XSTREAM.fromXML( reader ); 79 | } 80 | finally 81 | { 82 | IOUtil.close( reader ); 83 | } 84 | } 85 | 86 | /** 87 | * Saves the {@link WebappStructure} to the specified file. 88 | * 89 | * @param webappStructure the structure to save 90 | * @param targetFile the file to use to save the structure 91 | * @throws IOException if an error occurred while saving the webapp structure 92 | */ 93 | public void toXml( WebappStructure webappStructure, File targetFile ) 94 | throws IOException 95 | { 96 | // CHECKSTYLE_OFF: LineLength 97 | Writer writer = null; 98 | try 99 | { 100 | if ( !targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs() ) 101 | { 102 | throw new IOException( "Could not create parent [" + targetFile.getParentFile().getAbsolutePath() + "]" ); 103 | } 104 | 105 | if ( !targetFile.exists() && !targetFile.createNewFile() ) 106 | { 107 | throw new IOException( "Could not create file [" + targetFile.getAbsolutePath() + "]" ); 108 | } 109 | writer = WriterFactory.newXmlWriter( targetFile ); 110 | XSTREAM.toXML( webappStructure, writer ); 111 | } 112 | finally 113 | { 114 | IOUtil.close( writer ); 115 | } 116 | // CHECKSTYLE_ON: LineLength 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/util/ClassesPackager.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.util; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import cn.wanghaomiao.maven.plugin.seimi.packaging.AbstractWarPackagingTask; 23 | import org.apache.maven.archiver.MavenArchiveConfiguration; 24 | import org.apache.maven.archiver.MavenArchiver; 25 | import org.apache.maven.artifact.DependencyResolutionRequiredException; 26 | import org.apache.maven.execution.MavenSession; 27 | import org.apache.maven.plugin.MojoExecutionException; 28 | import org.apache.maven.project.MavenProject; 29 | import org.codehaus.plexus.archiver.ArchiverException; 30 | import org.codehaus.plexus.archiver.jar.JarArchiver; 31 | import org.codehaus.plexus.archiver.jar.ManifestException; 32 | 33 | import java.io.File; 34 | import java.io.IOException; 35 | 36 | /** 37 | * Packages the content of the classes directory. 38 | * 39 | * @author Stephane Nicoll 40 | * @version $Id: ClassesPackager.java 1628849 2014-10-01 22:03:26Z khmarbaise $ 41 | */ 42 | public class ClassesPackager 43 | { 44 | 45 | /** 46 | * Creates a new instance. 47 | */ 48 | public ClassesPackager() 49 | { 50 | super(); 51 | } 52 | 53 | /** 54 | * Package the classes 55 | * 56 | * @param classesDirectory the classes directory 57 | * @param targetFile the target file 58 | * @param jarArchiver the jar archiver to use 59 | * @param session the current session 60 | * @param project the related project 61 | * @param archiveConfiguration the archive configuration to use 62 | * @throws MojoExecutionException if an error occurred while creating the archive 63 | */ 64 | public void packageClasses( File classesDirectory, File targetFile, JarArchiver jarArchiver, MavenSession session, 65 | MavenProject project, MavenArchiveConfiguration archiveConfiguration ) 66 | throws MojoExecutionException 67 | { 68 | 69 | try 70 | { 71 | final MavenArchiver archiver = new MavenArchiver(); 72 | archiver.setArchiver( jarArchiver ); 73 | archiver.setOutputFile( targetFile ); 74 | archiver.getArchiver().addDirectory( classesDirectory ); 75 | archiver.createArchive( session, project, archiveConfiguration ); 76 | } 77 | catch ( ArchiverException e ) 78 | { 79 | throw new MojoExecutionException( "Could not create classes archive", e ); 80 | } 81 | catch ( ManifestException e ) 82 | { 83 | throw new MojoExecutionException( "Could not create classes archive", e ); 84 | } 85 | catch ( IOException e ) 86 | { 87 | throw new MojoExecutionException( "Could not create classes archive", e ); 88 | } 89 | catch ( DependencyResolutionRequiredException e ) 90 | { 91 | throw new MojoExecutionException( "Could not create classes archive", e ); 92 | } 93 | } 94 | 95 | /** 96 | * Returns the classes directory from the specified webapp directory. 97 | * 98 | * @param webappDirectory the webapp directory 99 | * @return the classes directory of the specified webapp directory 100 | */ 101 | public File getClassesDirectory( File webappDirectory ) 102 | { 103 | return new File( webappDirectory, AbstractWarPackagingTask.CLASSES_PATH ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/ClassesPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.artifact.Artifact; 23 | import org.apache.maven.artifact.factory.ArtifactFactory; 24 | import org.apache.maven.plugin.MojoExecutionException; 25 | import cn.wanghaomiao.maven.plugin.seimi.Overlay; 26 | import cn.wanghaomiao.maven.plugin.seimi.util.ClassesPackager; 27 | import cn.wanghaomiao.maven.plugin.seimi.util.PathSet; 28 | import org.apache.maven.project.MavenProject; 29 | import org.codehaus.plexus.interpolation.InterpolationException; 30 | 31 | import java.io.File; 32 | import java.io.IOException; 33 | 34 | /** 35 | * Handles the classes directory that needs to be packaged in the web application. 36 | *

37 | * Based on the {@link WarPackagingContext#archiveClasses()} flag the resources either copied into to 38 | * WEB-INF/classes directory or archived in a jar within the WEB-INF/lib directory. 39 | * 40 | * @author Stephane Nicoll 41 | * @version $Id: ClassesPackagingTask.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 42 | */ 43 | public class ClassesPackagingTask 44 | extends AbstractWarPackagingTask 45 | { 46 | private final Overlay currentProjectOverlay; 47 | 48 | /** 49 | * @param currentProjectOverlay {@link #currentProjectOverlay} 50 | */ 51 | public ClassesPackagingTask( Overlay currentProjectOverlay ) 52 | { 53 | this.currentProjectOverlay = currentProjectOverlay; 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | public void performPackaging( WarPackagingContext context ) 60 | throws MojoExecutionException 61 | { 62 | final File webappClassesDirectory = new File( context.getWebappDirectory(), CLASSES_PATH ); 63 | if ( !webappClassesDirectory.exists() ) 64 | { 65 | webappClassesDirectory.mkdirs(); 66 | } 67 | 68 | if ( context.getClassesDirectory().exists() && !context.getClassesDirectory().equals( webappClassesDirectory ) ) 69 | { 70 | if ( context.archiveClasses() ) 71 | { 72 | generateJarArchive( context ); 73 | } 74 | else 75 | { 76 | final PathSet sources = getFilesToIncludes( context.getClassesDirectory(), null, null ); 77 | try 78 | { 79 | copyFiles( currentProjectOverlay.getId(), context, context.getClassesDirectory(), sources, 80 | CLASSES_PATH, false ); 81 | } 82 | catch ( IOException e ) 83 | { 84 | throw new MojoExecutionException( "Could not copy webapp classes [" 85 | + context.getClassesDirectory().getAbsolutePath() + "]", e ); 86 | } 87 | } 88 | } 89 | } 90 | 91 | /** 92 | * @param context The warPackingContext. 93 | * @throws MojoExecutionException In casae of an error. 94 | */ 95 | protected void generateJarArchive( WarPackagingContext context ) 96 | throws MojoExecutionException 97 | { 98 | MavenProject project = context.getProject(); 99 | ArtifactFactory factory = context.getArtifactFactory(); 100 | Artifact artifact = 101 | factory.createBuildArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(), "jar" ); 102 | String archiveName; 103 | try 104 | { 105 | archiveName = getArtifactFinalName( context, artifact ); 106 | } 107 | catch ( InterpolationException e ) 108 | { 109 | throw new MojoExecutionException( "Could not get the final name of the artifact [" + artifact.getGroupId() 110 | + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() + "]", e ); 111 | } 112 | final String targetFilename = LIB_PATH + archiveName; 113 | 114 | if ( context.getWebappStructure().registerFile( currentProjectOverlay.getId(), targetFilename ) ) 115 | { 116 | final File libDirectory = new File( context.getWebappDirectory(), LIB_PATH ); 117 | final File jarFile = new File( libDirectory, archiveName ); 118 | final ClassesPackager packager = new ClassesPackager(); 119 | packager.packageClasses( context.getClassesDirectory(), jarFile, context.getJarArchiver(), 120 | context.getSession(), project, context.getArchive() ); 121 | } 122 | else 123 | { 124 | context.getLog().warn( "Could not generate archive classes file [" + targetFilename 125 | + "] has already been copied." ); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 4.0.0 9 | 10 | 11 | org.sonatype.oss 12 | oss-parent 13 | 7 14 | 15 | cn.wanghaomiao 16 | maven-seimicrawler-plugin 17 | 1.3.0 18 | maven-plugin 19 | 20 | SeimiCrawler Package Plugin 21 | 22 | Package seimicrawler project so that can be fast and standalone deployed.It is based on maven-war-plugin and modified. 23 | 这是专为SeimiCrawler工程专门定制的一个maven发布工具,意在简化开发者项目发布与部署流程。本插件是基于Apache的maven-war-plugin修改而来,依然采用Apache License Version2.0发布。 24 | 25 | 26 | 27 | 2.6 28 | 1.3 29 | 2.2.1 30 | 31 | 32 | 33 | 34 | Auke Schrijnen 35 | 36 | 37 | Ludwig Magnusson 38 | 39 | 40 | Hayarobi Park 41 | 42 | 43 | Haomiao Wang 44 | 45 | 46 | 47 | 48 | 49 | org.apache.maven 50 | maven-plugin-api 51 | ${mavenVersion} 52 | 53 | 54 | org.apache.maven 55 | maven-artifact 56 | ${mavenVersion} 57 | 58 | 59 | org.apache.maven 60 | maven-model 61 | ${mavenVersion} 62 | 63 | 64 | org.apache.maven 65 | maven-project 66 | ${mavenVersion} 67 | 68 | 69 | org.apache.maven 70 | maven-core 71 | ${mavenVersion} 72 | 73 | 74 | org.apache.maven 75 | maven-settings 76 | ${mavenVersion} 77 | 78 | 79 | org.apache.maven 80 | maven-archiver 81 | ${mavenArchiverVersion} 82 | 83 | 84 | org.apache.maven.plugin-tools 85 | maven-plugin-annotations 86 | 3.4 87 | provided 88 | 89 | 90 | org.codehaus.plexus 91 | plexus-io 92 | 2.4.1 93 | 94 | 95 | commons-io 96 | commons-io 97 | 2.2 98 | 99 | 100 | org.codehaus.plexus 101 | plexus-archiver 102 | 2.9 103 | 104 | 105 | org.codehaus.plexus 106 | plexus-interpolation 107 | 1.21 108 | 109 | 110 | 111 | com.thoughtworks.xstream 112 | xstream 113 | 1.4.4 114 | 115 | 116 | 117 | org.codehaus.plexus 118 | plexus-utils 119 | 3.0.20 120 | 121 | 122 | 123 | org.apache.maven.shared 124 | maven-filtering 125 | ${mavenFilteringVersion} 126 | 127 | 128 | 129 | org.apache.maven.shared 130 | maven-mapping 131 | 1.0 132 | 133 | 134 | org.freemarker 135 | freemarker 136 | 2.3.23 137 | 138 | 139 | 140 | junit 141 | junit 142 | 4.11 143 | test 144 | 145 | 146 | org.apache.maven.plugin-testing 147 | maven-plugin-testing-harness 148 | 1.3 149 | test 150 | 151 | 152 | 153 | 154 | 155 | org.apache.maven.plugins 156 | maven-plugin-plugin 157 | 3.2 158 | 159 | true 160 | 161 | 162 | 163 | mojo-descriptor 164 | 165 | descriptor 166 | 167 | 168 | 169 | help-goal 170 | 171 | helpmojo 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/util/WarUtils.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.util; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.artifact.Artifact; 23 | import org.apache.maven.model.Dependency; 24 | import org.apache.maven.project.MavenProject; 25 | import org.codehaus.plexus.util.StringUtils; 26 | 27 | /** 28 | * @author Stephane Nicoll 29 | * @version $Id: WarUtils.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 30 | */ 31 | public class WarUtils 32 | { 33 | 34 | /** 35 | * @param project {@link MavenProject} 36 | * @param dependency {@link Dependency} 37 | * @return {@link Artifact} 38 | */ 39 | public static Artifact getArtifact( MavenProject project, Dependency dependency ) 40 | { 41 | for ( Object o : project.getArtifacts() ) 42 | { 43 | Artifact artifact = (Artifact) o; 44 | if ( artifact.getGroupId().equals( dependency.getGroupId() ) 45 | && artifact.getArtifactId().equals( dependency.getArtifactId() ) 46 | && artifact.getType().equals( dependency.getType() ) ) 47 | { 48 | if ( artifact.getClassifier() == null && dependency.getClassifier() == null ) 49 | { 50 | return artifact; 51 | } 52 | else if ( dependency.getClassifier() != null 53 | && dependency.getClassifier().equals( artifact.getClassifier() ) ) 54 | { 55 | return artifact; 56 | } 57 | } 58 | } 59 | return null; 60 | } 61 | 62 | /** 63 | * @param artifact {@link Artifact} 64 | * @param dependency {@link Dependency} 65 | * @return is related or not. 66 | */ 67 | public static boolean isRelated( Artifact artifact, Dependency dependency ) 68 | { 69 | if ( artifact == null || dependency == null ) 70 | { 71 | return false; 72 | } 73 | 74 | if ( !StringUtils.equals( artifact.getGroupId(), dependency.getGroupId() ) ) 75 | { 76 | return false; 77 | } 78 | if ( !StringUtils.equals( artifact.getArtifactId(), dependency.getArtifactId() ) ) 79 | { 80 | return false; 81 | } 82 | if ( artifact.getVersion() != null ? !artifact.getVersion().equals( dependency.getVersion() ) 83 | : dependency.getVersion() != null ) 84 | { 85 | return false; 86 | } 87 | if ( artifact.getType() != null ? !artifact.getType().equals( dependency.getType() ) 88 | : dependency.getType() != null ) 89 | { 90 | return false; 91 | } 92 | if ( artifact.getClassifier() != null ? !artifact.getClassifier().equals( dependency.getClassifier() ) 93 | : dependency.getClassifier() != null ) 94 | { 95 | return false; 96 | } 97 | if ( artifact.getScope() != null ? !artifact.getScope().equals( dependency.getScope() ) 98 | : dependency.getScope() != null ) 99 | { 100 | return false; 101 | } 102 | if ( artifact.isOptional() != dependency.isOptional() ) 103 | { 104 | return false; 105 | } 106 | 107 | return true; 108 | } 109 | 110 | /** 111 | * @param first {@link Dependency} 112 | * @param second {@link Dependency} 113 | * @return are the dependencies equal. 114 | */ 115 | public static boolean dependencyEquals( Dependency first, Dependency second ) 116 | { 117 | if ( first == second ) 118 | { 119 | return true; 120 | } 121 | 122 | if ( first.isOptional() != second.isOptional() ) 123 | { 124 | return false; 125 | } 126 | if ( !StringUtils.equals( first.getArtifactId(), second.getArtifactId() ) ) 127 | { 128 | return false; 129 | } 130 | if ( first.getClassifier() != null ? !first.getClassifier().equals( second.getClassifier() ) 131 | : second.getClassifier() != null ) 132 | { 133 | return false; 134 | } 135 | if ( first.getExclusions() != null ? !first.getExclusions().equals( second.getExclusions() ) 136 | : second.getExclusions() != null ) 137 | { 138 | return false; 139 | } 140 | if ( !StringUtils.equals( first.getGroupId(), second.getGroupId() ) ) 141 | { 142 | return false; 143 | } 144 | if ( first.getScope() != null ? !first.getScope().equals( second.getScope() ) : second.getScope() != null ) 145 | { 146 | return false; 147 | } 148 | if ( first.getSystemPath() != null ? !first.getSystemPath().equals( second.getSystemPath() ) 149 | : second.getSystemPath() != null ) 150 | { 151 | return false; 152 | } 153 | if ( first.getType() != null ? !first.getType().equals( second.getType() ) : second.getType() != null ) 154 | { 155 | return false; 156 | } 157 | if ( first.getVersion() != null ? !first.getVersion().equals( second.getVersion() ) 158 | : second.getVersion() != null ) 159 | { 160 | return false; 161 | } 162 | return true; 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/OverlayPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import cn.wanghaomiao.maven.plugin.seimi.util.PathSet; 23 | import org.apache.maven.plugin.MojoExecutionException; 24 | import cn.wanghaomiao.maven.plugin.seimi.Overlay; 25 | import org.codehaus.plexus.util.FileUtils; 26 | 27 | import java.io.File; 28 | import java.io.IOException; 29 | 30 | /** 31 | * Handles an overlay. 32 | * 33 | * @author Stephane Nicoll 34 | * @version $Id: OverlayPackagingTask.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 35 | */ 36 | public class OverlayPackagingTask 37 | extends AbstractWarPackagingTask 38 | { 39 | private final Overlay overlay; 40 | 41 | /** 42 | * @param overlay {@link #overlay} 43 | * @param currentProjectOverlay current overlay. 44 | */ 45 | public OverlayPackagingTask( Overlay overlay, Overlay currentProjectOverlay ) 46 | { 47 | if ( overlay == null ) 48 | { 49 | throw new NullPointerException( "overlay could not be null." ); 50 | } 51 | if ( overlay.equals( currentProjectOverlay ) ) 52 | { 53 | throw new IllegalStateException( "Could not handle the current project with this task." ); 54 | } 55 | this.overlay = overlay; 56 | } 57 | 58 | /** 59 | * {@inheritDoc} 60 | */ 61 | public void performPackaging( WarPackagingContext context ) 62 | throws MojoExecutionException 63 | { 64 | context.getLog().debug( "OverlayPackagingTask performPackaging overlay.getTargetPath() " 65 | + overlay.getTargetPath() ); 66 | if ( overlay.shouldSkip() ) 67 | { 68 | context.getLog().info( "Skipping overlay [" + overlay + "]" ); 69 | } 70 | else 71 | { 72 | try 73 | { 74 | context.getLog().info( "Processing overlay [" + overlay + "]" ); 75 | 76 | // Step1: Extract if necessary 77 | final File tmpDir = unpackOverlay( context, overlay ); 78 | 79 | // Step2: setup 80 | final PathSet includes = getFilesToIncludes( tmpDir, overlay.getIncludes(), overlay.getExcludes() ); 81 | 82 | // Copy 83 | if ( null == overlay.getTargetPath() ) 84 | { 85 | copyFiles( overlay.getId(), context, tmpDir, includes, overlay.isFiltered() ); 86 | } 87 | else 88 | { 89 | // overlay.getTargetPath() must ended with / 90 | // if not we add it 91 | String targetPath = overlay.getTargetPath(); 92 | if ( !targetPath.endsWith( "/" ) ) 93 | { 94 | targetPath = targetPath + "/"; 95 | } 96 | copyFiles( overlay.getId(), context, tmpDir, includes, targetPath, overlay.isFiltered() ); 97 | } 98 | } 99 | catch ( IOException e ) 100 | { 101 | throw new MojoExecutionException( "Failed to copy file for overlay [" + overlay + "]", e ); 102 | } 103 | } 104 | } 105 | 106 | /** 107 | * Unpacks the specified overlay. 108 | *

109 | * Makes sure to skip the unpack process if the overlay has already been unpacked. 110 | * 111 | * @param context the packaging context 112 | * @param overlay the overlay 113 | * @return the directory containing the unpacked overlay 114 | * @throws MojoExecutionException if an error occurred while unpacking the overlay 115 | */ 116 | protected File unpackOverlay( WarPackagingContext context, Overlay overlay ) 117 | throws MojoExecutionException 118 | { 119 | final File tmpDir = getOverlayTempDirectory( context, overlay ); 120 | 121 | // TODO: not sure it's good, we should reuse the markers of the dependency plugin 122 | if ( FileUtils.sizeOfDirectory( tmpDir ) == 0 123 | || overlay.getArtifact().getFile().lastModified() > tmpDir.lastModified() ) 124 | { 125 | doUnpack( context, overlay.getArtifact().getFile(), tmpDir ); 126 | } 127 | else 128 | { 129 | context.getLog().debug( "Overlay [" + overlay + "] was already unpacked" ); 130 | } 131 | return tmpDir; 132 | } 133 | 134 | /** 135 | * Returns the directory to use to unpack the specified overlay. 136 | * 137 | * @param context the packaging context 138 | * @param overlay the overlay 139 | * @return the temp directory for the overlay 140 | */ 141 | protected File getOverlayTempDirectory( WarPackagingContext context, Overlay overlay ) 142 | { 143 | final File groupIdDir = new File( context.getOverlaysWorkDirectory(), overlay.getGroupId() ); 144 | if ( !groupIdDir.exists() ) 145 | { 146 | groupIdDir.mkdir(); 147 | } 148 | String directoryName = overlay.getArtifactId(); 149 | if ( overlay.getClassifier() != null ) 150 | { 151 | directoryName = directoryName + "-" + overlay.getClassifier(); 152 | } 153 | final File result = new File( groupIdDir, directoryName ); 154 | if ( !result.exists() ) 155 | { 156 | result.mkdirs(); 157 | } 158 | return result; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/WarPackagingContext.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import java.io.File; 23 | import java.util.List; 24 | 25 | import cn.wanghaomiao.maven.plugin.seimi.util.WebappStructure; 26 | import org.apache.maven.archiver.MavenArchiveConfiguration; 27 | import org.apache.maven.artifact.factory.ArtifactFactory; 28 | import org.apache.maven.execution.MavenSession; 29 | import org.apache.maven.plugin.logging.Log; 30 | import org.apache.maven.project.MavenProject; 31 | import org.apache.maven.shared.filtering.MavenFileFilter; 32 | import org.apache.maven.shared.utils.io.FileUtils.FilterWrapper; 33 | import org.codehaus.plexus.archiver.jar.JarArchiver; 34 | import org.codehaus.plexus.archiver.manager.ArchiverManager; 35 | 36 | /** 37 | * The packaging context. 38 | * 39 | * @author Stephane Nicoll 40 | * @version $Id: WarPackagingContext.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 41 | */ 42 | public interface WarPackagingContext 43 | { 44 | /** 45 | * Returns the maven project. 46 | * 47 | * @return the project 48 | */ 49 | MavenProject getProject(); 50 | 51 | /** 52 | * Returns the webapp directory. Packaging tasks should use this directory to generate the webapp. 53 | * 54 | * @return the webapp directory 55 | */ 56 | File getWebappDirectory(); 57 | 58 | /** 59 | * Returns the main webapp source directory. 60 | * 61 | * @return the webapp source directory 62 | */ 63 | File getWebappSourceDirectory(); 64 | 65 | /** 66 | * Returns the webapp source includes. 67 | * 68 | * @return the webapp source includes 69 | */ 70 | String[] getWebappSourceIncludes(); 71 | 72 | /** 73 | * Returns {@code true} if empty directories should be includes, othewrwise {@code false} 74 | * 75 | * @return {@code true} if empty directories should be includes, othewrwise {@code false} 76 | */ 77 | boolean isWebappSourceIncludeEmptyDirectories(); 78 | 79 | /** 80 | * Returns the webapp source excludes. 81 | * 82 | * @return the webapp source excludes 83 | */ 84 | String[] getWebappSourceExcludes(); 85 | 86 | /** 87 | * Returns the directory holding generated classes. 88 | * 89 | * @return the classes directory 90 | */ 91 | File getClassesDirectory(); 92 | 93 | /** 94 | * Specify whether the classes resources should be archived in the WEB-INF/lib of the generated web app. 95 | * 96 | * @return true if the classes should be archived, false otherwise 97 | */ 98 | boolean archiveClasses(); 99 | 100 | /** 101 | * Returns the logger to use to output logging event. 102 | * 103 | * @return the logger 104 | */ 105 | Log getLog(); 106 | 107 | /** 108 | * Returns the directory to unpack dependent WARs into if needed. 109 | * 110 | * @return the overlays work directory 111 | */ 112 | File getOverlaysWorkDirectory(); 113 | 114 | /** 115 | * Returns the archiver manager to use. 116 | * 117 | * @return the archiver manager 118 | */ 119 | ArchiverManager getArchiverManager(); 120 | 121 | /** 122 | * The maven archive configuration to use. 123 | * 124 | * @return the maven archive configuration 125 | */ 126 | MavenArchiveConfiguration getArchive(); 127 | 128 | /** 129 | * Returns the Jar archiver needed for archiving classes directory into jar file under WEB-INF/lib. 130 | * 131 | * @return the jar archiver to user 132 | */ 133 | JarArchiver getJarArchiver(); 134 | 135 | /** 136 | * Returns the output file name mapping to use, if any. Returns null if no file name mapping is set. 137 | * 138 | * @return the output file name mapping or null 139 | */ 140 | String getOutputFileNameMapping(); 141 | 142 | /** 143 | * Returns the list of filter files to use. 144 | * 145 | * @return a list of filter files 146 | */ 147 | List getFilters(); 148 | 149 | /** 150 | * Returns the {@link WebappStructure}. 151 | * 152 | * @return the webapp structure 153 | */ 154 | WebappStructure getWebappStructure(); 155 | 156 | /** 157 | * Returns the list of registered overlays for this session. This list might differ from the one returned by the 158 | * cache; in this case, it means that the project's configuration has changed. The plugin will handle those cases 159 | * nicely but it would be better in general to invoke the clean goal. 160 | * 161 | * @return the list of registered overlays, including the current project 162 | */ 163 | List getOwnerIds(); 164 | 165 | /** 166 | * Returns the {@link MavenFileFilter} instance to use. 167 | * 168 | * @return the maven file filter to use 169 | * @since 2.1-alpha-2 170 | */ 171 | MavenFileFilter getMavenFileFilter(); 172 | 173 | /** 174 | * @return {@link List} of {@link FilterWrapper} 175 | * @since 2.1-alpha-2 176 | */ 177 | List getFilterWrappers(); 178 | 179 | /** 180 | * Specify if the given fileName belongs to the list of extensions that must not be filtered 181 | * 182 | * @param fileName the name of file 183 | * @return true if it should not be filtered, false otherwise 184 | * @since 2.1-alpha-2 185 | */ 186 | boolean isNonFilteredExtension( String fileName ); 187 | 188 | /** 189 | * @return filtering deployment descriptor. 190 | */ 191 | boolean isFilteringDeploymentDescriptors(); 192 | 193 | /** 194 | * @return {@link ArtifactFactory} 195 | */ 196 | ArtifactFactory getArtifactFactory(); 197 | 198 | /** 199 | * Returns the Maven session. 200 | * 201 | * @return the Maven session 202 | * @since 2.2 203 | */ 204 | MavenSession getSession(); 205 | 206 | /** 207 | * Returns the encoding to use for resources. 208 | * 209 | * @return the resource encoding 210 | * @since 2.3 211 | */ 212 | String getResourceEncoding(); 213 | 214 | /** 215 | * @return to use jvmChmod rather than forking chmod cli 216 | * @since 2.4 217 | */ 218 | boolean isUseJvmChmod(); 219 | } 220 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/ArtifactsPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import java.io.IOException; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | import java.util.Set; 26 | 27 | import org.apache.maven.artifact.Artifact; 28 | import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; 29 | import org.apache.maven.plugin.MojoExecutionException; 30 | import cn.wanghaomiao.maven.plugin.seimi.Overlay; 31 | import org.codehaus.plexus.interpolation.InterpolationException; 32 | 33 | /** 34 | * Handles the artifacts that needs to be packaged in the web application. 35 | * 36 | * @author Stephane Nicoll 37 | * @version $Id: ArtifactsPackagingTask.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 38 | */ 39 | public class ArtifactsPackagingTask 40 | extends AbstractWarPackagingTask 41 | { 42 | 43 | /** 44 | * The {@code tld} path. 45 | */ 46 | public static final String TLD_PATH = "WEB-INF/tld/"; 47 | 48 | /** 49 | * The {@code services} path. 50 | */ 51 | public static final String SERVICES_PATH = "WEB-INF/services/"; 52 | 53 | /** 54 | * The {@code modules} path. 55 | */ 56 | public static final String MODULES_PATH = "WEB-INF/modules/"; 57 | 58 | /** 59 | * The {@code extensions} path. 60 | */ 61 | public static final String EXTENSIONS_PATH = "WEB-INF/extensions/"; 62 | 63 | private final Set artifacts; 64 | 65 | private final String id; 66 | 67 | /** 68 | * @param artifacts {@link #artifacts} 69 | * @param currentProjectOverlay {@link #id} 70 | */ 71 | public ArtifactsPackagingTask( Set artifacts, Overlay currentProjectOverlay ) 72 | { 73 | this.artifacts = artifacts; 74 | this.id = currentProjectOverlay.getId(); 75 | } 76 | 77 | /** 78 | * {@inheritDoc} 79 | */ 80 | public void performPackaging( WarPackagingContext context ) 81 | throws MojoExecutionException 82 | { 83 | try 84 | { 85 | final ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME ); 86 | final List duplicates = findDuplicates( context, artifacts ); 87 | 88 | for ( Artifact artifact : artifacts ) 89 | { 90 | String targetFileName = getArtifactFinalName( context, artifact ); 91 | 92 | context.getLog().debug( "Processing: " + targetFileName ); 93 | 94 | if ( duplicates.contains( targetFileName ) ) 95 | { 96 | context.getLog().debug( "Duplicate found: " + targetFileName ); 97 | targetFileName = artifact.getGroupId() + "-" + targetFileName; 98 | context.getLog().debug( "Renamed to: " + targetFileName ); 99 | } 100 | context.getWebappStructure().registerTargetFileName( artifact, targetFileName ); 101 | 102 | if ( !artifact.isOptional() && filter.include( artifact ) ) 103 | { 104 | try 105 | { 106 | String type = artifact.getType(); 107 | if ( "tld".equals( type ) ) 108 | { 109 | copyFile( id, context, artifact.getFile(), TLD_PATH + targetFileName ); 110 | } 111 | else if ( "aar".equals( type ) ) 112 | { 113 | copyFile( id, context, artifact.getFile(), SERVICES_PATH + targetFileName ); 114 | } 115 | else if ( "mar".equals( type ) ) 116 | { 117 | copyFile( id, context, artifact.getFile(), MODULES_PATH + targetFileName ); 118 | } 119 | else if ( "xar".equals( type ) ) 120 | { 121 | copyFile( id, context, artifact.getFile(), EXTENSIONS_PATH + targetFileName ); 122 | } 123 | else if ( "jar".equals( type ) || "ejb".equals( type ) || "ejb-client".equals( type ) 124 | || "test-jar".equals( type ) || "bundle".equals( type ) ) 125 | { 126 | copyFile( id, context, artifact.getFile(), LIB_PATH + targetFileName ); 127 | } 128 | else if ( "par".equals( type ) ) 129 | { 130 | targetFileName = targetFileName.substring( 0, targetFileName.lastIndexOf( '.' ) ) + ".jar"; 131 | copyFile( id, context, artifact.getFile(), LIB_PATH + targetFileName ); 132 | } 133 | else if ( "war".equals( type ) ) 134 | { 135 | // Nothing to do here, it is an overlay and it's already handled 136 | context.getLog().debug( "war artifacts are handled as overlays, ignoring [" + artifact 137 | + "]" ); 138 | } 139 | else if ( "zip".equals( type ) ) 140 | { 141 | // Nothing to do here, it is an overlay and it's already handled 142 | context.getLog().debug( "zip artifacts are handled as overlays, ignoring [" + artifact 143 | + "]" ); 144 | } 145 | else 146 | { 147 | context.getLog().debug( "Artifact of type [" + type + "] is not supported, ignoring [" 148 | + artifact + "]" ); 149 | } 150 | } 151 | catch ( IOException e ) 152 | { 153 | throw new MojoExecutionException( "Failed to copy file for artifact [" + artifact + "]", e ); 154 | } 155 | } 156 | } 157 | } 158 | catch ( InterpolationException e ) 159 | { 160 | throw new MojoExecutionException( e.getMessage(), e ); 161 | } 162 | } 163 | 164 | /** 165 | * Searches a set of artifacts for duplicate filenames and returns a list of duplicates. 166 | * 167 | * @param context the packaging context 168 | * @param artifacts set of artifacts 169 | * @return List of duplicated artifacts as bundling file names 170 | */ 171 | private List findDuplicates( WarPackagingContext context, Set artifacts ) 172 | throws InterpolationException 173 | { 174 | List duplicates = new ArrayList(); 175 | List identifiers = new ArrayList(); 176 | for ( Artifact artifact : artifacts ) 177 | { 178 | String candidate = getArtifactFinalName( context, artifact ); 179 | if ( identifiers.contains( candidate ) ) 180 | { 181 | duplicates.add( candidate ); 182 | } 183 | else 184 | { 185 | identifiers.add( candidate ); 186 | } 187 | } 188 | return duplicates; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/util/PathSet.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.util; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.codehaus.plexus.util.DirectoryScanner; 23 | import org.codehaus.plexus.util.StringUtils; 24 | 25 | import java.io.File; 26 | import java.util.Collection; 27 | import java.util.HashSet; 28 | import java.util.Iterator; 29 | import java.util.LinkedHashSet; 30 | import java.util.Set; 31 | 32 | /** 33 | * Set of file's paths. 34 | *

35 | * The class extends functionality of a "normal" set of strings by a process of the paths normalization. All paths are 36 | * converted to unix form (slashes) and they don't start with starting /. 37 | * 38 | * @author Piotr Tabor 39 | * @version $Id: PathSet.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 40 | */ 41 | 42 | public class PathSet 43 | implements Iterable 44 | { 45 | 46 | /** 47 | * Set of normalized paths 48 | */ 49 | private Set pathsSet = new LinkedHashSet(); 50 | 51 | /** 52 | * The method normalizes the path. 53 | *

54 | *

58 | * 59 | * @param path to normalization 60 | * @return normalized path 61 | */ 62 | protected String normalizeFilePath( String path ) 63 | { 64 | return normalizeFilePathStatic( path ); 65 | } 66 | 67 | /*-------------------- Business interface ------------------------------*/ 68 | 69 | /** 70 | * Creates an empty paths set 71 | */ 72 | public PathSet() 73 | { 74 | /* Empty default constructor */ 75 | } 76 | 77 | /** 78 | * Creates paths set and normalizate and adds all 'paths'. The source 'paths' will not be changed 79 | * 80 | * @param paths to be added 81 | */ 82 | public PathSet( Collection paths ) 83 | { 84 | addAll( paths ); 85 | } 86 | 87 | /** 88 | * Creates paths set and normalizate and adds all 'paths'. The source 'paths' will not be changed 89 | * 90 | * @param paths to be added 91 | */ 92 | public PathSet( String[] paths ) 93 | { 94 | addAll( paths ); 95 | } 96 | 97 | /** 98 | * Normalizes and adds given path to the set. 99 | * 100 | * @param path to be added 101 | */ 102 | public void add( String path ) 103 | { 104 | pathsSet.add( normalizeFilePath( path ) ); 105 | } 106 | 107 | /** 108 | * Normalizes and adds given paths (collection of strings) to the set. The source collection will not be changed 109 | * 110 | * @param paths - collection of strings to be added 111 | * @param prefix added to all given paths 112 | */ 113 | public void addAll( Collection paths, String prefix ) 114 | { 115 | for ( String val : paths ) 116 | { 117 | add( prefix + val ); 118 | } 119 | } 120 | 121 | /** 122 | * Normalizes and adds given paths to the set. The source collection will not be changed 123 | * 124 | * @param paths to be added 125 | * @param prefix added to all given paths 126 | */ 127 | public void addAll( String[] paths, String prefix ) 128 | { 129 | for ( String val : paths ) 130 | { 131 | add( prefix + val ); 132 | } 133 | } 134 | 135 | /** 136 | * Adds given paths to the set. The source collection will not be changed 137 | * 138 | * @param paths to be added 139 | * @param prefix added to all given paths 140 | */ 141 | public void addAll( PathSet paths, String prefix ) 142 | { 143 | for ( String path : paths ) 144 | { 145 | add( prefix + path ); 146 | } 147 | } 148 | 149 | /** 150 | * Normalizes and adds given paths (collection of strings) to the set. The source collection will not be changed 151 | * 152 | * @param paths - collection of strings to be added 153 | */ 154 | public void addAll( Collection paths ) 155 | { 156 | addAll( paths, "" ); 157 | } 158 | 159 | /** 160 | * Normalizes and adds given paths to the set. The source collection will not be changed 161 | * 162 | * @param paths to be added 163 | */ 164 | public void addAll( String[] paths ) 165 | { 166 | addAll( paths, "" ); 167 | } 168 | 169 | /** 170 | * Adds given paths to the set. The source collection will not be changed 171 | * 172 | * @param paths to be added 173 | */ 174 | public void addAll( PathSet paths ) 175 | { 176 | addAll( paths, "" ); 177 | } 178 | 179 | /** 180 | * Checks if the set constains given path. The path is normalized before check. 181 | * 182 | * @param path we are looking for in the set. 183 | * @return information if the set constains the path. 184 | */ 185 | public boolean contains( String path ) 186 | { 187 | return pathsSet.contains( normalizeFilePath( path ) ); 188 | } 189 | 190 | /** 191 | * Removes the specified path if it exists. 192 | * 193 | * @param path the path to remove 194 | * @return true if the path was removed, false if it did not existed 195 | */ 196 | boolean remove( String path ) 197 | { 198 | final String normalizedPath = normalizeFilePath( path ); 199 | return pathsSet.remove( normalizedPath ); 200 | 201 | } 202 | 203 | /** 204 | * Returns iterator of normalized paths (strings) 205 | * 206 | * @return iterator of normalized paths (strings) 207 | */ 208 | public Iterator iterator() 209 | { 210 | return pathsSet.iterator(); 211 | } 212 | 213 | /** 214 | * @return {@link #pathsSet} 215 | */ 216 | public Collection paths() 217 | { 218 | return pathsSet; 219 | } 220 | 221 | /** 222 | * Adds given prefix to all paths in the set. 223 | *

224 | * The prefix should be ended by '/'. The generated paths are normalized. 225 | * 226 | * @param prefix to be added to all items 227 | */ 228 | public void addPrefix( String prefix ) 229 | { 230 | final Set newSet = new HashSet(); 231 | for ( String path : pathsSet ) 232 | { 233 | newSet.add( normalizeFilePath( prefix + path ) ); 234 | } 235 | pathsSet = newSet; 236 | } 237 | 238 | /** 239 | * Returns count of the paths in the set 240 | * 241 | * @return count of the paths in the set 242 | */ 243 | public int size() 244 | { 245 | return pathsSet.size(); 246 | } 247 | 248 | /** 249 | * Adds to the set all files in the given directory 250 | * 251 | * @param directory that will be searched for file's paths to add 252 | * @param prefix to be added to all found files 253 | */ 254 | public void addAllFilesInDirectory( File directory, String prefix ) 255 | { 256 | DirectoryScanner scanner = new DirectoryScanner(); 257 | scanner.setBasedir( directory ); 258 | scanner.scan(); 259 | addAll( scanner.getIncludedFiles(), prefix ); 260 | } 261 | 262 | /*-------------------- Universal static mathods ------------------------*/ 263 | /** 264 | * The method normalizes the path. 265 | *

266 | *

    267 | *
  • changes directory separator to unix's separator(/)
  • 268 | *
  • deletes all trailing slashes
  • 269 | *
270 | * 271 | * @param path to normalization 272 | * @return normalized path 273 | */ 274 | public static String normalizeFilePathStatic( String path ) 275 | { 276 | return trimTrailingSlashes( StringUtils.replace( path, '\\', '/' ) ); 277 | } 278 | 279 | /** 280 | * The method deletes all trailing slashes from the given string 281 | * 282 | * @param str a string 283 | * @return trimed string 284 | */ 285 | public static String trimTrailingSlashes( String str ) 286 | { 287 | int i; 288 | for ( i = 0; i < str.length() && str.charAt( i ) == '/'; i++ ) 289 | { 290 | // just calculate i 291 | } 292 | return str.substring( i ); 293 | } 294 | 295 | } 296 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/overlay/OverlayManager.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.overlay; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import java.util.ArrayList; 23 | import java.util.Arrays; 24 | import java.util.List; 25 | import java.util.ListIterator; 26 | import java.util.Set; 27 | 28 | import org.apache.maven.artifact.Artifact; 29 | import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter; 30 | import cn.wanghaomiao.maven.plugin.seimi.Overlay; 31 | import org.apache.maven.project.MavenProject; 32 | import org.codehaus.plexus.util.StringUtils; 33 | 34 | /** 35 | * Manages the overlays. 36 | * 37 | * @author Stephane Nicoll 38 | * @version $Id: OverlayManager.java 1636820 2014-11-05 08:27:25Z khmarbaise $ 39 | */ 40 | public class OverlayManager 41 | { 42 | private final List overlays; 43 | 44 | private final MavenProject project; 45 | 46 | private final List artifactsOverlays; 47 | 48 | /** 49 | * Creates a manager with the specified overlays. 50 | *

51 | * Note that the list is potentially updated by the manager so a new list is created based on the overlays. 52 | * 53 | * @param overlays the overlays 54 | * @param project the maven project 55 | * @param defaultIncludes the default includes to use 56 | * @param defaultExcludes the default excludes to use 57 | * @param currentProjectOverlay the overlay for the current project 58 | * @throws InvalidOverlayConfigurationException if the config is invalid 59 | */ 60 | public OverlayManager( List overlays, MavenProject project, String defaultIncludes, 61 | String defaultExcludes, Overlay currentProjectOverlay ) 62 | throws InvalidOverlayConfigurationException 63 | { 64 | this.overlays = new ArrayList(); 65 | if ( overlays != null ) 66 | { 67 | this.overlays.addAll( overlays ); 68 | } 69 | this.project = project; 70 | 71 | this.artifactsOverlays = getOverlaysAsArtifacts(); 72 | 73 | // Initialize 74 | initialize( defaultIncludes, defaultExcludes, currentProjectOverlay ); 75 | 76 | } 77 | 78 | /** 79 | * Returns the resolved overlays. 80 | * 81 | * @return the overlays 82 | */ 83 | public List getOverlays() 84 | { 85 | return overlays; 86 | } 87 | 88 | /** 89 | * Returns the id of the resolved overlays. 90 | * 91 | * @return the overlay ids 92 | */ 93 | public List getOverlayIds() 94 | { 95 | final List result = new ArrayList(); 96 | for ( Overlay overlay : overlays ) 97 | { 98 | result.add( overlay.getId() ); 99 | } 100 | return result; 101 | 102 | } 103 | 104 | /** 105 | * Initializes the manager and validates the overlays configuration. 106 | * 107 | * @param defaultIncludes the default includes to use 108 | * @param defaultExcludes the default excludes to use 109 | * @param currentProjectOverlay the overlay for the current project 110 | * @throws InvalidOverlayConfigurationException if the configuration is invalid 111 | */ 112 | void initialize( String defaultIncludes, String defaultExcludes, Overlay currentProjectOverlay ) 113 | throws InvalidOverlayConfigurationException 114 | { 115 | 116 | // Build the list of configured artifacts and makes sure that each overlay 117 | // refer to a valid artifact 118 | final List configuredWarArtifacts = new ArrayList(); 119 | final ListIterator it = overlays.listIterator(); 120 | while ( it.hasNext() ) 121 | { 122 | Overlay overlay = it.next(); 123 | if ( overlay == null ) 124 | { 125 | throw new InvalidOverlayConfigurationException( "overlay could not be null." ); 126 | } 127 | // If it's the current project, return the project instance 128 | if ( overlay.isCurrentProject() ) 129 | { 130 | overlay = currentProjectOverlay; 131 | it.set( overlay ); 132 | } 133 | // default includes/excludes - only if the overlay uses the default settings 134 | if ( Arrays.equals( Overlay.DEFAULT_INCLUDES, overlay.getIncludes() ) 135 | && Arrays.equals( Overlay.DEFAULT_EXCLUDES, overlay.getExcludes() ) ) 136 | { 137 | overlay.setIncludes( defaultIncludes ); 138 | overlay.setExcludes( defaultExcludes ); 139 | } 140 | 141 | final Artifact artifact = getAssociatedArtifact( overlay ); 142 | if ( artifact != null ) 143 | { 144 | configuredWarArtifacts.add( artifact ); 145 | overlay.setArtifact( artifact ); 146 | } 147 | } 148 | 149 | // Build the list of missing overlays 150 | for ( Artifact artifact : artifactsOverlays ) 151 | { 152 | if ( !configuredWarArtifacts.contains( artifact ) ) 153 | { 154 | // Add a default overlay for the given artifact which will be applied after 155 | // the ones that have been configured 156 | overlays.add( new DefaultOverlay( artifact, defaultIncludes, defaultExcludes ) ); 157 | } 158 | } 159 | 160 | // Final validation, make sure that the current project is in there. Otherwise add it first 161 | for ( Overlay overlay : overlays ) 162 | { 163 | if ( overlay.equals( currentProjectOverlay ) ) 164 | { 165 | return; 166 | } 167 | } 168 | overlays.add( 0, currentProjectOverlay ); 169 | } 170 | 171 | /** 172 | * Returns the Artifact associated to the specified overlay. 173 | *

174 | * If the overlay defines the current project, null is returned. If no artifact could not be found for the 175 | * overlay a InvalidOverlayConfigurationException is thrown. 176 | * 177 | * @param overlay an overlay 178 | * @return the artifact associated to the overlay 179 | * @throws InvalidOverlayConfigurationException if the overlay does not have an 180 | * associated artifact 181 | */ 182 | Artifact getAssociatedArtifact( final Overlay overlay ) 183 | throws InvalidOverlayConfigurationException 184 | { 185 | if ( overlay.isCurrentProject() ) 186 | { 187 | return null; 188 | } 189 | 190 | for ( Artifact artifact : artifactsOverlays ) 191 | { 192 | // Handle classifier dependencies properly (clash management) 193 | if ( compareOverlayWithArtifact( overlay, artifact ) ) 194 | { 195 | return artifact; 196 | } 197 | } 198 | 199 | // maybe its a project dependencies zip or an other type 200 | @SuppressWarnings( "unchecked" ) 201 | Set projectArtifacts = this.project.getDependencyArtifacts(); 202 | if ( projectArtifacts != null ) 203 | { 204 | for ( Artifact artifact : projectArtifacts ) 205 | { 206 | if ( compareOverlayWithArtifact( overlay, artifact ) ) 207 | { 208 | return artifact; 209 | } 210 | } 211 | } 212 | // CHECKSTYLE_OFF: LineLength 213 | throw new InvalidOverlayConfigurationException( "overlay [" + overlay + "] is not a dependency of the project." ); 214 | // CHECKSTYLE_ON: LineLength 215 | 216 | } 217 | 218 | /** 219 | * Compare groupId && artifactId && type && classifier. 220 | * 221 | * @param overlay the overlay 222 | * @param artifact the artifact 223 | * @return boolean true if equals 224 | */ 225 | private boolean compareOverlayWithArtifact( Overlay overlay, Artifact artifact ) 226 | { 227 | return ( StringUtils.equals( overlay.getGroupId(), artifact.getGroupId() ) 228 | && StringUtils.equals( overlay.getArtifactId(), artifact.getArtifactId() ) 229 | && StringUtils.equals( overlay.getType(), artifact.getType() ) 230 | // MWAR-241 Make sure to treat null and "" as equal when comparing the classifier 231 | && StringUtils.equals( StringUtils.defaultString( overlay.getClassifier() ), 232 | StringUtils.defaultString( artifact.getClassifier() ) ) ); 233 | } 234 | 235 | /** 236 | * Returns a list of WAR {@link org.apache.maven.artifact.Artifact} describing the overlays of the current project. 237 | * 238 | * @return the overlays as artifacts objects 239 | */ 240 | private List getOverlaysAsArtifacts() 241 | { 242 | ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME ); 243 | @SuppressWarnings( "unchecked" ) 244 | final Set artifacts = project.getArtifacts(); 245 | 246 | final List result = new ArrayList(); 247 | for ( Artifact artifact : artifacts ) 248 | { 249 | if ( !artifact.isOptional() && filter.include( artifact ) && ( "war".equals( artifact.getType() ) ) ) 250 | { 251 | result.add( artifact ); 252 | } 253 | } 254 | return result; 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/main/resources/template/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | SEIMI_HOME=$(cd `dirname $0`; cd ..; pwd) 3 | #https://github.com/rudimeier/bash_ini_parser 4 | function read_ini() 5 | { 6 | S_SECTION=$2; S_ITEM=$3 7 | # Be strict with the prefix, since it's going to be run through eval 8 | function check_prefix() 9 | { 10 | if ! [[ "${VARNAME_PREFIX}" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] ;then 11 | echo "read_ini: invalid prefix '${VARNAME_PREFIX}'" >&2 12 | return 1 13 | fi 14 | } 15 | function check_ini_file() 16 | { 17 | if [ ! -r "$INI_FILE" ] ;then 18 | echo "read_ini: '${INI_FILE}' doesn't exist or not" \ 19 | "readable" >&2 20 | return 1 21 | fi 22 | } 23 | # enable some optional shell behavior (shopt) 24 | function pollute_bash() 25 | { 26 | if ! shopt -q extglob ;then 27 | SWITCH_SHOPT="${SWITCH_SHOPT} extglob" 28 | fi 29 | if ! shopt -q nocasematch ;then 30 | SWITCH_SHOPT="${SWITCH_SHOPT} nocasematch" 31 | fi 32 | shopt -q -s ${SWITCH_SHOPT} 33 | } 34 | # unset all local functions and restore shopt settings before returning 35 | # from read_ini() 36 | function cleanup_bash() 37 | { 38 | shopt -q -u ${SWITCH_SHOPT} 39 | unset -f check_prefix check_ini_file pollute_bash cleanup_bash 40 | } 41 | local INI_FILE="" 42 | local INI_SECTION="" 43 | # {{{ START Deal with command line args 44 | 45 | # Set defaults 46 | local BOOLEANS=1 47 | local VARNAME_PREFIX=INI 48 | local CLEAN_ENV=0 49 | 50 | # {{{ START Options 51 | 52 | # Available options: 53 | # --boolean Whether to recognise special boolean values: ie for 'yes', 'true' 54 | # and 'on' return 1; for 'no', 'false' and 'off' return 0. Quoted 55 | # values will be left as strings 56 | # Default: on 57 | # 58 | # --prefix=STRING String to begin all returned variables with (followed by '__'). 59 | # Default: INI 60 | # 61 | # First non-option arg is filename, second is section name 62 | while [ $# -gt 0 ] 63 | do 64 | case $1 in 65 | --clean | -c ) 66 | CLEAN_ENV=1 67 | ;; 68 | --booleans | -b ) 69 | shift 70 | BOOLEANS=$1 71 | ;; 72 | --prefix | -p ) 73 | shift 74 | VARNAME_PREFIX=$1 75 | ;; 76 | * ) 77 | if [ -z "$INI_FILE" ] 78 | then 79 | INI_FILE=$1 80 | else 81 | if [ -z "$INI_SECTION" ] 82 | then 83 | INI_SECTION=$1 84 | fi 85 | fi 86 | ;; 87 | esac 88 | shift 89 | done 90 | if [ -z "$INI_FILE" ] && [ "${CLEAN_ENV}" = 0 ] ;then 91 | echo -e "Usage: read_ini [-c] [-b 0| -b 1]] [-p PREFIX] FILE"\ 92 | "[SECTION]\n or read_ini -c [-p PREFIX]" >&2 93 | cleanup_bash 94 | return 1 95 | fi 96 | if ! check_prefix ;then 97 | cleanup_bash 98 | return 1 99 | fi 100 | local INI_ALL_VARNAME="${VARNAME_PREFIX}__ALL_VARS" 101 | local INI_ALL_SECTION="${VARNAME_PREFIX}__ALL_SECTIONS" 102 | local INI_NUMSECTIONS_VARNAME="${VARNAME_PREFIX}__NUMSECTIONS" 103 | if [ "${CLEAN_ENV}" = 1 ] ;then 104 | eval unset "\$${INI_ALL_VARNAME}" 105 | fi 106 | unset ${INI_ALL_VARNAME} 107 | unset ${INI_ALL_SECTION} 108 | unset ${INI_NUMSECTIONS_VARNAME} 109 | if [ -z "$INI_FILE" ] ;then 110 | cleanup_bash 111 | return 0 112 | fi 113 | if ! check_ini_file ;then 114 | cleanup_bash 115 | return 1 116 | fi 117 | # Sanitise BOOLEANS - interpret "0" as 0, anything else as 1 118 | if [ "$BOOLEANS" != "0" ] 119 | then 120 | BOOLEANS=1 121 | fi 122 | # }}} END Options 123 | # }}} END Deal with command line args 124 | local LINE_NUM=0 125 | local SECTIONS_NUM=0 126 | local SECTION="" 127 | # IFS is used in "read" and we want to switch it within the loop 128 | local IFS=$' \t\n' 129 | local IFS_OLD="${IFS}" 130 | # we need some optional shell behavior (shopt) but want to restore 131 | # current settings before returning 132 | local SWITCH_SHOPT="" 133 | pollute_bash 134 | TARGET_VAR=${VARNAME_PREFIX}__${S_SECTION}__${S_ITEM} 135 | while read -r line || [ -n "$line" ] 136 | do 137 | ((LINE_NUM++)) 138 | # Skip blank lines and comments 139 | if [ -z "$line" -o "${line:0:1}" = ";" -o "${line:0:1}" = "#" ] 140 | then 141 | continue 142 | fi 143 | # Section marker? 144 | if [[ "${line}" =~ ^\[[a-zA-Z0-9_]{1,}\]$ ]] 145 | then 146 | # Set SECTION var to name of section (strip [ and ] from section marker) 147 | SECTION="${line#[}" 148 | SECTION="${SECTION%]}" 149 | eval "${INI_ALL_SECTION}=\"\${${INI_ALL_SECTION}# } $SECTION\"" 150 | ((SECTIONS_NUM++)) 151 | continue 152 | fi 153 | # Are we getting only a specific section? And are we currently in it? 154 | if [ ! -z "$INI_SECTION" ] 155 | then 156 | if [ "$SECTION" != "$INI_SECTION" ] 157 | then 158 | continue 159 | fi 160 | fi 161 | # Valid var/value line? (check for variable name and then '=') 162 | if ! [[ "${line}" =~ ^[a-zA-Z0-9._]{1,}[[:space:]]*= ]] 163 | then 164 | echo "Error: Invalid line:" >&2 165 | echo " ${LINE_NUM}: $line" >&2 166 | cleanup_bash 167 | return 1 168 | fi 169 | # split line at "=" sign 170 | IFS="=" 171 | read -r VAR VAL <<< "${line}" 172 | IFS="${IFS_OLD}" 173 | 174 | # delete spaces around the equal sign (using extglob) 175 | VAR="${VAR%%+([[:space:]])}" 176 | VAL="${VAL##+([[:space:]])}" 177 | VAR=$(echo $VAR) 178 | # Construct variable name: 179 | # ${VARNAME_PREFIX}__$SECTION__$VAR 180 | # Or if not in a section: 181 | # ${VARNAME_PREFIX}__$VAR 182 | # In both cases, full stops ('.') are replaced with underscores ('_') 183 | if [ -z "$SECTION" ] 184 | then 185 | VARNAME=${VARNAME_PREFIX}__${VAR//./_} 186 | else 187 | VARNAME=${VARNAME_PREFIX}__${SECTION}__${VAR//./_} 188 | fi 189 | eval "${INI_ALL_VARNAME}=\"\${${INI_ALL_VARNAME}# } ${VARNAME}\"" 190 | 191 | if [[ "${VAL}" =~ ^\".*\"$ ]] 192 | then 193 | # remove existing double quotes 194 | VAL="${VAL##\"}" 195 | VAL="${VAL%%\"}" 196 | elif [[ "${VAL}" =~ ^\'.*\'$ ]] 197 | then 198 | # remove existing single quotes 199 | VAL="${VAL##\'}" 200 | VAL="${VAL%%\'}" 201 | elif [ "$BOOLEANS" = 1 ] 202 | then 203 | # Value is not enclosed in quotes 204 | # Booleans processing is switched on, check for special boolean 205 | # values and convert 206 | # here we compare case insensitive because 207 | # "shopt nocasematch" 208 | case "$VAL" in 209 | yes | true | on ) 210 | VAL=1 211 | ;; 212 | no | false | off ) 213 | VAL=0 214 | ;; 215 | esac 216 | fi 217 | # enclose the value in single quotes and escape any 218 | # single quotes and backslashes that may be in the value 219 | VAL="${VAL//\\/\\\\}" 220 | #VAL="\$'${VAL//\'/\'}'" 221 | if [[ $VARNAME = $TARGET_VAR ]] 222 | then 223 | echo "${VAL}" 224 | break 225 | fi 226 | done <"${INI_FILE}" 227 | cleanup_bash 228 | } 229 | function usage(){ 230 | cat<$SEIMI_STDOUT 2>&1 & 253 | PID=`echo $!` 254 | if [ -d "/proc/$PID" ]; then 255 | echo $!>"$SEIMI_HOME/.seimicrawler.lock.pid" 256 | echo "[Info]SeimiCrawler started,pid: $PID" 257 | else 258 | echo "[Error]SeimiCrawler start failed ,you can see more info in $SEIMI_STDOUT." 259 | fi 260 | exit 0 261 | } 262 | 263 | function stop(){ 264 | if [ -f "$SEIMI_HOME/.seimicrawler.lock.pid" ]; then 265 | echo "SeimiCrawler pid file is ok." 266 | else 267 | echo "No SeimiCrawler instance is alive,home dir: $SEIMI_HOME" 268 | exit 0 269 | fi 270 | pid=$(cat $SEIMI_HOME/.seimicrawler.lock.pid) 271 | if [ ! -d "/proc/$pid" ]; then 272 | echo "No SeimiCrawler instance is running,pid:$pid" 273 | rm "$SEIMI_HOME/.seimicrawler.lock.pid" 274 | exit 0 275 | else 276 | kill $pid 277 | if [ $? -eq 0 ]; then 278 | echo "Stop current SeimiCrawler instance,pid:$pid" 279 | rm "$SEIMI_HOME/.seimicrawler.lock.pid" 280 | exit 0 281 | else 282 | echo "Stop current SeimiCrawler instance failed,pid:$pid" 283 | fi 284 | fi 285 | rm "$SEIMI_HOME/.seimicrawler.lock.pid" 286 | exit 0 287 | } 288 | for arg ;do 289 | case "$arg" in 290 | help) usage ;; 291 | start) start;; 292 | stop) stop;; 293 | esac 294 | done 295 | 296 | usage -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/Overlay.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.artifact.Artifact; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | import java.util.List; 27 | 28 | /** 29 | * An overlay is a skeleton WAR added to another WAR project in order to inject a functionality, resources or any other 30 | * shared component. 31 | *

32 | * Note that a particular WAR dependency can be added multiple times as an overlay with different includes/excludes 33 | * filter; this allows building a fine grained overwriting policy. 34 | *

35 | * The current project can also be described as an overlay and can not be specified twice. An overlay with no groupId 36 | * and no artifactId represents the current project. 37 | * 38 | * @author Stephane Nicoll 39 | * @version $Id: Overlay.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 40 | */ 41 | public class Overlay 42 | { 43 | 44 | /** 45 | * The list of default includes. 46 | */ 47 | public static final String[] DEFAULT_INCLUDES = new String[] { "**/**" }; 48 | 49 | /** 50 | * The list of default excludes. 51 | */ 52 | public static final String[] DEFAULT_EXCLUDES = new String[] { "META-INF/MANIFEST.MF" }; 53 | 54 | private String id; 55 | 56 | private String groupId; 57 | 58 | private String artifactId; 59 | 60 | private String classifier = null; 61 | 62 | private String[] includes = DEFAULT_INCLUDES; 63 | 64 | private String[] excludes = DEFAULT_EXCLUDES; 65 | 66 | private boolean filtered = false; 67 | 68 | private boolean skip = false; 69 | 70 | private Artifact artifact; 71 | 72 | private String targetPath; 73 | 74 | /** default overlay type is war */ 75 | private String type = "war"; 76 | 77 | /** 78 | * Create instance. 79 | */ 80 | public Overlay() 81 | { 82 | super(); 83 | } 84 | 85 | /** 86 | * @param groupId {@link #groupId} 87 | * @param artifactId {@link #artifactId} 88 | */ 89 | public Overlay( String groupId, String artifactId ) 90 | { 91 | this(); 92 | this.groupId = groupId; 93 | this.artifactId = artifactId; 94 | } 95 | 96 | /** 97 | * Specify whether this overlay represents the current project or not. 98 | * 99 | * @return true if the overlay represents the current project, false otherwise 100 | */ 101 | public boolean isCurrentProject() 102 | { 103 | return ( groupId == null && artifactId == null ); 104 | } 105 | 106 | /** 107 | * @return {@link Overlay} instance. 108 | */ 109 | public static Overlay createInstance() 110 | { 111 | Overlay overlay = new Overlay(); 112 | overlay.setId( "currentBuild" ); 113 | return overlay; 114 | } 115 | 116 | // Getters and Setters 117 | 118 | /** 119 | * @return The id. 120 | */ 121 | public String getId() 122 | { 123 | if ( id == null ) 124 | { 125 | final StringBuilder sb = new StringBuilder(); 126 | sb.append( getGroupId() ).append( ":" ).append( getArtifactId() ); 127 | if ( getClassifier() != null ) 128 | { 129 | sb.append( ":" ).append( getClassifier() ); 130 | } 131 | id = sb.toString(); 132 | } 133 | return id; 134 | } 135 | 136 | /** 137 | * @param id The id. 138 | */ 139 | public void setId( String id ) 140 | { 141 | this.id = id; 142 | } 143 | 144 | /** 145 | * @return {@link #groupId} 146 | */ 147 | public String getGroupId() 148 | { 149 | return groupId; 150 | } 151 | 152 | /** 153 | * @param groupId {@link #groupId} 154 | */ 155 | public void setGroupId( String groupId ) 156 | { 157 | this.groupId = groupId; 158 | } 159 | 160 | /** 161 | * @return {@link #artifactId} 162 | */ 163 | public String getArtifactId() 164 | { 165 | return artifactId; 166 | } 167 | 168 | /** 169 | * @param artifactId {@link #artifactId} 170 | */ 171 | public void setArtifactId( String artifactId ) 172 | { 173 | this.artifactId = artifactId; 174 | } 175 | 176 | /** 177 | * @return {@link #classifier} 178 | */ 179 | public String getClassifier() 180 | { 181 | return classifier; 182 | } 183 | 184 | /** 185 | * @param classifier {@link #classifier} 186 | */ 187 | public void setClassifier( String classifier ) 188 | { 189 | this.classifier = classifier; 190 | } 191 | 192 | /** 193 | * @return {@link #includes} 194 | */ 195 | public String[] getIncludes() 196 | { 197 | return includes; 198 | } 199 | 200 | /** 201 | * @param includes {@link #includes} 202 | */ 203 | public void setIncludes( String includes ) 204 | { 205 | this.includes = parse( includes ); 206 | } 207 | 208 | /** 209 | * @param includes {@link #includes} 210 | */ 211 | public void setIncludes( String[] includes ) 212 | { 213 | this.includes = includes; 214 | } 215 | 216 | /** 217 | * @return {@link #excludes} 218 | */ 219 | public String[] getExcludes() 220 | { 221 | return excludes; 222 | } 223 | 224 | /** 225 | * @param excludes {@link #excludes} 226 | */ 227 | public void setExcludes( String excludes ) 228 | { 229 | this.excludes = parse( excludes ); 230 | } 231 | 232 | /** 233 | * @param excludes {@link #excludes} 234 | */ 235 | public void setExcludes( String[] excludes ) 236 | { 237 | this.excludes = excludes; 238 | } 239 | 240 | /** 241 | * @return {@link #filtered} 242 | */ 243 | public boolean isFiltered() 244 | { 245 | return filtered; 246 | } 247 | 248 | /** 249 | * @param filtered {@link #filtered} 250 | */ 251 | public void setFiltered( boolean filtered ) 252 | { 253 | this.filtered = filtered; 254 | } 255 | 256 | /** 257 | * @return {@link #skip} 258 | */ 259 | public boolean shouldSkip() 260 | { 261 | return skip; 262 | } 263 | 264 | /** 265 | * @param skip {@link #skip} 266 | */ 267 | public void setSkip( boolean skip ) 268 | { 269 | this.skip = skip; 270 | } 271 | 272 | /** 273 | * @return {@link #artifact} 274 | */ 275 | public Artifact getArtifact() 276 | { 277 | return artifact; 278 | } 279 | 280 | /** 281 | * @param artifact {@link #artifact} 282 | */ 283 | public void setArtifact( Artifact artifact ) 284 | { 285 | this.artifact = artifact; 286 | } 287 | 288 | /** 289 | * @return {@link #targetPath} 290 | */ 291 | public String getTargetPath() 292 | { 293 | return targetPath; 294 | } 295 | 296 | /** 297 | * @param targetPath {@link #targetPath} 298 | */ 299 | public void setTargetPath( String targetPath ) 300 | { 301 | this.targetPath = targetPath; 302 | } 303 | 304 | /** 305 | * @return {@link #type} 306 | */ 307 | public String getType() 308 | { 309 | return type; 310 | } 311 | 312 | /** 313 | * @param type {@link #type} 314 | */ 315 | public void setType( String type ) 316 | { 317 | this.type = type; 318 | } 319 | 320 | /** 321 | * {@inheritDoc} 322 | */ 323 | public String toString() 324 | { 325 | return " id " + getId(); 326 | } 327 | 328 | /** 329 | * {@inheritDoc} 330 | */ 331 | public boolean equals( Object o ) 332 | { 333 | if ( this == o ) 334 | { 335 | return true; 336 | } 337 | if ( o == null || getClass() != o.getClass() ) 338 | { 339 | return false; 340 | } 341 | 342 | Overlay overlay = (Overlay) o; 343 | 344 | if ( excludes != null ? !Arrays.equals( excludes, overlay.excludes ) : overlay.excludes != null ) 345 | { 346 | return false; 347 | } 348 | if ( getId() != null ? !getId().equals( overlay.getId() ) : overlay.getId() != null ) 349 | { 350 | return false; 351 | } 352 | if ( includes != null ? !Arrays.equals( includes, overlay.includes ) : overlay.includes != null ) 353 | { 354 | return false; 355 | } 356 | 357 | return true; 358 | } 359 | 360 | /** 361 | * {@inheritDoc} 362 | */ 363 | public int hashCode() 364 | { 365 | int result; 366 | result = ( getId() != null ? getId().hashCode() : 0 ); 367 | result = 31 * result + ( includes != null ? includes.hashCode() : 0 ); 368 | result = 31 * result + ( excludes != null ? excludes.hashCode() : 0 ); 369 | return result; 370 | } 371 | 372 | private String[] parse( String s ) 373 | { 374 | final List result = new ArrayList(); 375 | if ( s == null ) 376 | { 377 | return result.toArray( new String[result.size()] ); 378 | } 379 | else 380 | { 381 | String[] tokens = s.split( "," ); 382 | for ( String token : tokens ) 383 | { 384 | result.add( token.trim() ); 385 | } 386 | return result.toArray( new String[result.size()] ); 387 | } 388 | } 389 | 390 | } 391 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/DependenciesAnalysisPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import cn.wanghaomiao.maven.plugin.seimi.util.WebappStructure; 23 | import org.apache.maven.artifact.Artifact; 24 | import org.apache.maven.model.Dependency; 25 | import org.apache.maven.plugin.MojoExecutionException; 26 | import org.apache.maven.plugin.MojoFailureException; 27 | 28 | import java.io.File; 29 | 30 | /** 31 | * Analyzes the dependencies of the project with its previous state and update the target directory accordingly. 32 | * 33 | * @author Stephane Nicoll 34 | * @version $Id: DependenciesAnalysisPackagingTask.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 35 | */ 36 | public class DependenciesAnalysisPackagingTask 37 | extends AbstractWarPackagingTask 38 | { 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | public void performPackaging( final WarPackagingContext context ) 44 | throws MojoExecutionException, MojoFailureException 45 | { 46 | 47 | context.getWebappStructure().analyseDependencies( new DependenciesAnalysisCallbackImpl( context ) ); 48 | 49 | } 50 | 51 | /** 52 | * {@inheritDoc} 53 | */ 54 | protected void handleDependency( WarPackagingContext context, Dependency dependency, String notBundledMessage, 55 | String warOrZipMessage, String standardMessage, boolean removeFile ) 56 | { 57 | if ( Artifact.SCOPE_PROVIDED.equals( dependency.getScope() ) 58 | || Artifact.SCOPE_TEST.equals( dependency.getScope() ) || dependency.isOptional() ) 59 | { 60 | context.getLog().debug( notBundledMessage ); 61 | } 62 | else 63 | { 64 | handleDependencyScope( context, dependency, warOrZipMessage, standardMessage, removeFile ); 65 | } 66 | } 67 | 68 | /** 69 | * {@inheritDoc} 70 | */ 71 | protected void handleDependencyScope( WarPackagingContext context, Dependency dependency, String warOrZipMessage, 72 | String standardMessage, boolean removeFile ) 73 | { 74 | if ( "war".equals( dependency.getType() ) || "zip".equals( dependency.getType() ) ) 75 | { 76 | context.getLog().warn( warOrZipMessage ); 77 | } 78 | else if ( "tld".equals( dependency.getType() ) || "aar".equals( dependency.getType() ) 79 | || "mar".equals( dependency.getType() ) || "xar".equals( dependency.getType() ) 80 | || "jar".equals( dependency.getType() ) || "ejb".equals( dependency.getType() ) 81 | || "ejb-client".equals( dependency.getType() ) || "test-jar".equals( dependency.getType() ) 82 | || "par".equals( dependency.getType() ) ) 83 | { 84 | context.getLog().info( standardMessage ); 85 | if ( removeFile ) 86 | { 87 | removeDependency( context, dependency ); 88 | } 89 | } 90 | } 91 | 92 | private void removeDependency( WarPackagingContext context, Dependency dependency ) 93 | { 94 | final String targetFileName = context.getWebappStructure().getCachedTargetFileName( dependency ); 95 | if ( targetFileName != null ) 96 | { 97 | final String type = dependency.getType(); 98 | File targetFile = null; 99 | if ( "tld".equals( type ) ) 100 | { 101 | targetFile = new File( context.getWebappDirectory(), ArtifactsPackagingTask.TLD_PATH + targetFileName ); 102 | } 103 | else if ( "aar".equals( type ) ) 104 | { 105 | targetFile = 106 | new File( context.getWebappDirectory(), ArtifactsPackagingTask.SERVICES_PATH + targetFileName ); 107 | } 108 | else if ( "mar".equals( type ) ) 109 | { 110 | targetFile = 111 | new File( context.getWebappDirectory(), ArtifactsPackagingTask.MODULES_PATH + targetFileName ); 112 | } 113 | else if ( "xar".equals( type ) ) 114 | { 115 | targetFile = 116 | new File( context.getWebappDirectory(), ArtifactsPackagingTask.EXTENSIONS_PATH + targetFileName ); 117 | } 118 | else if ( "jar".equals( type ) || "ejb".equals( type ) || "ejb-client".equals( type ) 119 | || "test-jar".equals( type ) ) 120 | { 121 | targetFile = new File( context.getWebappDirectory(), LIB_PATH + targetFileName ); 122 | } 123 | else if ( "par".equals( type ) ) 124 | { 125 | String targetFileName2 = targetFileName.substring( 0, targetFileName.lastIndexOf( '.' ) ) + ".jar"; 126 | targetFile = new File( context.getWebappDirectory(), LIB_PATH + targetFileName2 ); 127 | } 128 | 129 | // now remove 130 | if ( targetFile == null ) 131 | { 132 | context.getLog().error( "Could not get file from dependency [" + dependency + "]" ); 133 | } 134 | else if ( targetFile.exists() ) 135 | { 136 | context.getLog().debug( "Removing file [" + targetFile.getAbsolutePath() + "]" ); 137 | targetFile.delete(); 138 | } 139 | else 140 | { 141 | context.getLog().warn( "File to remove [" + targetFile.getAbsolutePath() + "] has not been found" ); 142 | } 143 | } 144 | else 145 | { 146 | context.getLog().warn( "Could not retrieve the target file name of dependency [" + dependency + "]" ); 147 | } 148 | } 149 | 150 | class DependenciesAnalysisCallbackImpl 151 | implements WebappStructure.DependenciesAnalysisCallback 152 | { 153 | private final WarPackagingContext context; 154 | 155 | DependenciesAnalysisCallbackImpl( WarPackagingContext context ) 156 | { 157 | this.context = context; 158 | } 159 | 160 | public void unchangedDependency( Dependency dependency ) 161 | { 162 | context.getLog().debug( "Dependency [" + dependency + "] has not changed since last build." ); 163 | } 164 | 165 | public void newDependency( Dependency dependency ) 166 | { 167 | context.getLog().debug( "New dependency [" + dependency + "]." ); 168 | } 169 | 170 | public void removedDependency( Dependency dependency ) 171 | { 172 | handleDependency( context, dependency, "Dependency [" + dependency 173 | + "] has been removed from the project but it was not bundled anyway.", "Dependency [" + dependency 174 | + "] has been removed from the project. If it was included in the build as an overlay, " 175 | + "consider cleaning the target directory of the project (mvn clean)", "Dependency [" + dependency 176 | + "] has been removed from the project.", true ); 177 | } 178 | 179 | public void updatedVersion( Dependency dependency, String previousVersion ) 180 | { 181 | handleDependency( context, dependency, "Version of dependency [" + dependency + "] has changed (" 182 | + previousVersion + " -> " + dependency.getVersion() 183 | + ") but it was not bundled anyway.", 184 | "Version of dependency [" + dependency + "] has changed (" + previousVersion + " -> " 185 | + dependency.getVersion() + "). If it was included in the build as an overlay, " 186 | + "consider " + "cleaning the target directory of the project (mvn clean)", 187 | "Version of dependency [" + dependency + "] has changed (" + previousVersion + " -> " 188 | + dependency.getVersion() + ").", true ); 189 | } 190 | 191 | public void updatedScope( Dependency dependency, String previousScope ) 192 | { 193 | // CHECKSTYLE_OFF: LineLength 194 | if ( Artifact.SCOPE_PROVIDED.equals( dependency.getScope() ) 195 | || Artifact.SCOPE_TEST.equals( dependency.getScope() ) 196 | && ( !Artifact.SCOPE_PROVIDED.equals( previousScope ) && !Artifact.SCOPE_TEST.equals( previousScope ) ) ) 197 | // CHECKSTYLE_ON: LineLength 198 | { 199 | // It's now provided or test so it should be removed 200 | handleDependencyScope( context, dependency, "Scope of dependency [" + dependency + "] has changed (" 201 | + previousScope + " -> " + dependency.getScope() 202 | + "). If it was included in the build as an overlay, " 203 | + "consider cleaning the target directory of the project (mvn clean)", "Scope of dependency [" 204 | + dependency + "] has changed (" + previousScope + " -> " + dependency.getScope() + ").", true ); 205 | } 206 | 207 | } 208 | 209 | public void updatedOptionalFlag( Dependency dependency, boolean previousOptional ) 210 | { 211 | if ( !previousOptional && dependency.isOptional() ) 212 | { 213 | // It wasn't optional but now it is anymore 214 | handleDependency( context, dependency, "Dependency [" + dependency 215 | + "] is now optional but it was not bundled anyway.", "Dependency [" + dependency 216 | + "] is now optional. If it was included in the build as an overlay, " 217 | + "consider cleaning the target directory of the project (mvn clean)", "Dependency [" + dependency 218 | + "] is now optional", true ); 219 | 220 | } 221 | } 222 | 223 | public void updatedUnknown( Dependency dependency, Dependency previousDep ) 224 | { 225 | handleDependency( context, dependency, "Dependency [" + dependency + "] has changed (was " + previousDep 226 | + ") but it was not bundled anyway.", "Dependency [" + dependency + "] has changed (was " + previousDep 227 | + "). If it was included in the build as an overlay, " + "consider " 228 | + "cleaning the target directory of the project (mvn clean)", "Dependency [" + dependency 229 | + "] has changed (was " + previousDep + ").", true ); 230 | } 231 | 232 | } 233 | 234 | } 235 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/SeimiMojo.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi; 2 | 3 | /* 4 | * Apache License Version2.0 5 | */ 6 | 7 | import org.apache.maven.archiver.MavenArchiver; 8 | import org.apache.maven.artifact.Artifact; 9 | import org.apache.maven.artifact.DependencyResolutionRequiredException; 10 | import org.apache.maven.plugin.MojoExecutionException; 11 | import org.apache.maven.plugin.MojoFailureException; 12 | import cn.wanghaomiao.maven.plugin.seimi.util.ClassesPackager; 13 | import org.apache.maven.plugins.annotations.Component; 14 | import org.apache.maven.plugins.annotations.LifecyclePhase; 15 | import org.apache.maven.plugins.annotations.Mojo; 16 | import org.apache.maven.plugins.annotations.Parameter; 17 | import org.apache.maven.plugins.annotations.ResolutionScope; 18 | import org.apache.maven.project.MavenProjectHelper; 19 | import org.codehaus.plexus.archiver.Archiver; 20 | import org.codehaus.plexus.archiver.ArchiverException; 21 | import org.codehaus.plexus.archiver.jar.ManifestException; 22 | import org.codehaus.plexus.archiver.war.WarArchiver; 23 | import org.codehaus.plexus.util.FileUtils; 24 | import org.codehaus.plexus.util.StringUtils; 25 | 26 | import java.io.File; 27 | import java.io.IOException; 28 | import java.util.Arrays; 29 | 30 | @Mojo(name = "build", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true, requiresDependencyResolution = ResolutionScope.RUNTIME) 31 | public class SeimiMojo extends AbstractWarMojo { 32 | /** 33 | * The directory for build. 34 | */ 35 | @Parameter(defaultValue = "${project.build.directory}", required = true) 36 | private String outputDirectory; 37 | 38 | /** 39 | * The name of the final package. 40 | */ 41 | @Parameter(defaultValue = "${project.build.finalName}", property = "war.warName", required = true) 42 | private String pkgName; 43 | 44 | /** 45 | * Classifier to add to the generated WAR. If given, the artifact will be an attachment instead. The classifier will 46 | * not be applied to the JAR file of the project - only to the WAR file. 47 | */ 48 | @Parameter 49 | private String classifier; 50 | 51 | /** 52 | * The comma separated list of tokens to exclude from the WAR before packaging. This option may be used to implement 53 | * the skinny WAR use case. Note that you can use the Java Regular Expressions engine to include and exclude 54 | * specific pattern using the expression %regex[]. Hint: read the about (?!Pattern). 55 | * 56 | * @since 2.1-alpha-2 57 | */ 58 | @Parameter 59 | private String packagingExcludes; 60 | 61 | /** 62 | * The comma separated list of tokens to include in the WAR before packaging. By default everything is included. 63 | * This option may be used to implement the skinny WAR use case. Note that you can use the Java Regular Expressions 64 | * engine to include and exclude specific pattern using the expression %regex[]. 65 | * 66 | * @since 2.1-beta-1 67 | */ 68 | @Parameter 69 | private String packagingIncludes; 70 | 71 | /** 72 | * The WAR archiver. 73 | */ 74 | @Component(role = Archiver.class, hint = "war") 75 | private WarArchiver warArchiver; 76 | 77 | /** 78 | */ 79 | @Component 80 | private MavenProjectHelper projectHelper; 81 | 82 | private boolean primaryArtifact = true; 83 | 84 | private boolean failOnMissingWebXml = false; 85 | 86 | /** 87 | * Whether classes (that is the content of the WEB-INF/classes directory) should be attached to the project as an 88 | * additional artifact. 89 | *

90 | * By default the classifier for the additional artifact is 'classes'. You can change it with the 91 | * someclassifier]]> parameter. 92 | *

93 | *

94 | * If this parameter true, another project can depend on the classes by writing something like: 95 | *

96 | *

 97 |      * 
 98 |      *   myGroup
 99 |      *   myArtifact
100 |      *   myVersion
101 |      *   classes
102 |      * ]]>
103 |      * 
104 | *

105 | *

106 | * 107 | * @since 2.1-alpha-2 108 | */ 109 | @Parameter(defaultValue = "false") 110 | private boolean attachClasses = false; 111 | 112 | /** 113 | * The classifier to use for the attached classes artifact. 114 | * 115 | * @since 2.1-alpha-2 116 | */ 117 | @Parameter(defaultValue = "classes") 118 | private String classesClassifier = "classes"; 119 | 120 | // ---------------------------------------------------------------------- 121 | // Implementation 122 | // ---------------------------------------------------------------------- 123 | 124 | /** 125 | * Executes the WarMojo on the current project. 126 | * 127 | * @throws MojoExecutionException if an error occurred while building the webapp 128 | * @throws MojoFailureException if an error. 129 | */ 130 | public void execute() 131 | throws MojoExecutionException, MojoFailureException { 132 | File warFile = getTargetWarFile(); 133 | 134 | try { 135 | performPackaging(warFile); 136 | } catch (DependencyResolutionRequiredException e) { 137 | throw new MojoExecutionException("Error assembling WAR: " + e.getMessage(), e); 138 | } catch (ManifestException e) { 139 | throw new MojoExecutionException("Error assembling WAR", e); 140 | } catch (IOException e) { 141 | throw new MojoExecutionException("Error assembling WAR", e); 142 | } catch (ArchiverException e) { 143 | throw new MojoExecutionException("Error assembling WAR: " + e.getMessage(), e); 144 | } 145 | } 146 | 147 | /** 148 | * Generates the webapp according to the mode attribute. 149 | * 150 | * @param warFile the target WAR file 151 | * @throws IOException if an error occurred while copying files 152 | * @throws ArchiverException if the archive could not be created 153 | * @throws ManifestException if the manifest could not be created 154 | * @throws DependencyResolutionRequiredException if an error occurred while resolving the dependencies 155 | * @throws MojoExecutionException if the execution failed 156 | * @throws MojoFailureException if a fatal exception occurred 157 | */ 158 | private void performPackaging(File warFile) 159 | throws IOException, ManifestException, DependencyResolutionRequiredException, MojoExecutionException, 160 | MojoFailureException { 161 | getLog().info("Packaging app"); 162 | 163 | buildExplodedWebapp(getWebappDirectory()); 164 | 165 | TemplateTask templateTask = new TemplateTask(getWebappDirectory(),getLog()); 166 | templateTask.createBinFile(); 167 | 168 | MavenArchiver archiver = new MavenArchiver(); 169 | 170 | archiver.setArchiver(warArchiver); 171 | 172 | archiver.setOutputFile(warFile); 173 | 174 | // CHECKSTYLE_OFF: LineLength 175 | getLog().debug("Excluding " + Arrays.asList(getPackagingExcludes()) + " from the generated app archive."); 176 | getLog().debug("Including " + Arrays.asList(getPackagingIncludes()) + " in the generated app archive."); 177 | // CHECKSTYLE_ON: LineLength 178 | 179 | warArchiver.addDirectory(getWebappDirectory(), getPackagingIncludes(), getPackagingExcludes()); 180 | 181 | // final File webXmlFile = new File(getWebappDirectory(), "WEB-INF/web.xml"); 182 | // if (webXmlFile.exists()) { 183 | // warArchiver.setWebxml(webXmlFile); 184 | // } 185 | 186 | warArchiver.setRecompressAddedZips(isRecompressZippedFiles()); 187 | 188 | warArchiver.setIncludeEmptyDirs(isIncludeEmptyDirectories()); 189 | 190 | if (!failOnMissingWebXml) { 191 | getLog().debug("Build won't fail if web.xml file is missing."); 192 | warArchiver.setExpectWebXml(false); 193 | } 194 | 195 | // create archive 196 | archiver.createArchive(getSession(), getProject(), getArchive()); 197 | 198 | // create the classes to be attached if necessary 199 | if (isAttachClasses()) { 200 | if (isArchiveClasses() && getJarArchiver().getDestFile() != null) { 201 | // special handling in case of archived classes: MWAR-240 202 | File targetClassesFile = getTargetClassesFile(); 203 | FileUtils.copyFile(getJarArchiver().getDestFile(), targetClassesFile); 204 | projectHelper.attachArtifact(getProject(), "jar", getClassesClassifier(), targetClassesFile); 205 | } else { 206 | ClassesPackager packager = new ClassesPackager(); 207 | final File classesDirectory = packager.getClassesDirectory(getWebappDirectory()); 208 | if (classesDirectory.exists()) { 209 | getLog().info("Packaging classes"); 210 | packager.packageClasses(classesDirectory, getTargetClassesFile(), getJarArchiver(), getSession(), 211 | getProject(), getArchive()); 212 | projectHelper.attachArtifact(getProject(), "jar", getClassesClassifier(), getTargetClassesFile()); 213 | } 214 | } 215 | } 216 | 217 | if (this.classifier != null) { 218 | projectHelper.attachArtifact(getProject(), "war", this.classifier, warFile); 219 | } else { 220 | Artifact artifact = getProject().getArtifact(); 221 | if (primaryArtifact) { 222 | artifact.setFile(warFile); 223 | } else if (artifact.getFile() == null || artifact.getFile().isDirectory()) { 224 | artifact.setFile(warFile); 225 | } 226 | } 227 | } 228 | 229 | /** 230 | * @param basedir The basedir 231 | * @param finalName The finalName 232 | * @param classifier The classifier. 233 | * @param type The type. 234 | * @return {@link File} 235 | */ 236 | protected static File getTargetFile(File basedir, String finalName, String classifier, String type) { 237 | if (classifier == null) { 238 | classifier = ""; 239 | } else if (classifier.trim().length() > 0 && !classifier.startsWith("-")) { 240 | classifier = "-" + classifier; 241 | } 242 | 243 | return new File(basedir, finalName + classifier + "." + type); 244 | } 245 | 246 | /** 247 | * @return The war {@link File} 248 | */ 249 | protected File getTargetWarFile() { 250 | return getTargetFile(new File(getOutputDirectory()), getPkgName(), getClassifier(), "zip"); 251 | 252 | } 253 | 254 | /** 255 | * @return The target class {@link File} 256 | */ 257 | protected File getTargetClassesFile() { 258 | return getTargetFile(new File(getOutputDirectory()), getPkgName(), getClassesClassifier(), "jar"); 259 | } 260 | 261 | // Getters and Setters 262 | 263 | /** 264 | * @return {@link #classifier} 265 | */ 266 | public String getClassifier() { 267 | return classifier; 268 | } 269 | 270 | /** 271 | * @param classifier {@link #classifier} 272 | */ 273 | public void setClassifier(String classifier) { 274 | this.classifier = classifier; 275 | } 276 | 277 | /** 278 | * @return The package excludes. 279 | */ 280 | public String[] getPackagingExcludes() { 281 | if (StringUtils.isEmpty(packagingExcludes)) { 282 | return new String[0]; 283 | } else { 284 | return StringUtils.split(packagingExcludes, ","); 285 | } 286 | } 287 | 288 | /** 289 | * @param packagingExcludes {@link #packagingExcludes} 290 | */ 291 | public void setPackagingExcludes(String packagingExcludes) { 292 | this.packagingExcludes = packagingExcludes; 293 | } 294 | 295 | /** 296 | * @return The packaging includes. 297 | */ 298 | public String[] getPackagingIncludes() { 299 | if (StringUtils.isEmpty(packagingIncludes)) { 300 | return new String[]{"**"}; 301 | } else { 302 | return StringUtils.split(packagingIncludes, ","); 303 | } 304 | } 305 | 306 | /** 307 | * @param packagingIncludes {@link #packagingIncludes} 308 | */ 309 | public void setPackagingIncludes(String packagingIncludes) { 310 | this.packagingIncludes = packagingIncludes; 311 | } 312 | 313 | /** 314 | * @return {@link #outputDirectory} 315 | */ 316 | public String getOutputDirectory() { 317 | return outputDirectory; 318 | } 319 | 320 | /** 321 | * @param outputDirectory {@link #outputDirectory} 322 | */ 323 | public void setOutputDirectory(String outputDirectory) { 324 | this.outputDirectory = outputDirectory; 325 | } 326 | 327 | /** 328 | * @return {@link #pkgName} 329 | */ 330 | public String getPkgName() { 331 | return pkgName; 332 | } 333 | 334 | /** 335 | * @param pkgName {@link #pkgName} 336 | */ 337 | public void setPkgName(String pkgName) { 338 | this.pkgName = pkgName; 339 | } 340 | 341 | /** 342 | * @return {@link #warArchiver} 343 | */ 344 | public WarArchiver getWarArchiver() { 345 | return warArchiver; 346 | } 347 | 348 | /** 349 | * @param warArchiver {@link #warArchiver} 350 | */ 351 | public void setWarArchiver(WarArchiver warArchiver) { 352 | this.warArchiver = warArchiver; 353 | } 354 | 355 | /** 356 | * @return {@link #projectHelper} 357 | */ 358 | public MavenProjectHelper getProjectHelper() { 359 | return projectHelper; 360 | } 361 | 362 | /** 363 | * @param projectHelper {@link #projectHelper} 364 | */ 365 | public void setProjectHelper(MavenProjectHelper projectHelper) { 366 | this.projectHelper = projectHelper; 367 | } 368 | 369 | /** 370 | * @return {@link #primaryArtifact} 371 | */ 372 | public boolean isPrimaryArtifact() { 373 | return primaryArtifact; 374 | } 375 | 376 | /** 377 | * @param primaryArtifact {@link #primaryArtifact} 378 | */ 379 | public void setPrimaryArtifact(boolean primaryArtifact) { 380 | this.primaryArtifact = primaryArtifact; 381 | } 382 | 383 | /** 384 | * @return {@link #attachClasses} 385 | */ 386 | public boolean isAttachClasses() { 387 | return attachClasses; 388 | } 389 | 390 | /** 391 | * @param attachClasses {@link #attachClasses} 392 | */ 393 | public void setAttachClasses(boolean attachClasses) { 394 | this.attachClasses = attachClasses; 395 | } 396 | 397 | /** 398 | * @return {@link #classesClassifier} 399 | */ 400 | public String getClassesClassifier() { 401 | return classesClassifier; 402 | } 403 | 404 | /** 405 | * @param classesClassifier {@link #classesClassifier} 406 | */ 407 | public void setClassesClassifier(String classesClassifier) { 408 | this.classesClassifier = classesClassifier; 409 | } 410 | 411 | /** 412 | * @return {@link #failOnMissingWebXml} 413 | */ 414 | public boolean isFailOnMissingWebXml() { 415 | return failOnMissingWebXml; 416 | } 417 | 418 | /** 419 | * @param failOnMissingWebXml {@link #failOnMissingWebXml} 420 | */ 421 | public void setFailOnMissingWebXml(boolean failOnMissingWebXml) { 422 | this.failOnMissingWebXml = failOnMissingWebXml; 423 | } 424 | } 425 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/WarProjectPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | 25 | import org.apache.maven.model.Resource; 26 | import org.apache.maven.plugin.MojoExecutionException; 27 | import org.apache.maven.plugin.MojoFailureException; 28 | import cn.wanghaomiao.maven.plugin.seimi.Overlay; 29 | import cn.wanghaomiao.maven.plugin.seimi.util.PathSet; 30 | import org.apache.maven.shared.filtering.MavenFilteringException; 31 | import org.codehaus.plexus.util.DirectoryScanner; 32 | import org.codehaus.plexus.util.StringUtils; 33 | 34 | /** 35 | * Handles the project own resources, that is:
    The list of web resources, if any
  • The content of the 36 | * webapp directory if it exists
  • The custom deployment descriptor(s), if any
  • The content of the 37 | * classes directory if it exists
  • The dependencies of the project
38 | * 39 | * @author Stephane Nicoll 40 | * @version $Id: WarProjectPackagingTask.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 41 | */ 42 | public class WarProjectPackagingTask 43 | extends AbstractWarPackagingTask 44 | { 45 | private final Resource[] webResources; 46 | 47 | private final File webXml; 48 | 49 | private final File containerConfigXML; 50 | 51 | private final String id; 52 | 53 | private Overlay currentProjectOverlay; 54 | 55 | /** 56 | * @param webResources {@link #webResources} 57 | * @param webXml {@link #webXml} 58 | * @param containerConfigXml {@link #containerConfigXML} 59 | * @param currentProjectOverlay {@link #currentProjectOverlay} 60 | */ 61 | public WarProjectPackagingTask( Resource[] webResources, File webXml, File containerConfigXml, 62 | Overlay currentProjectOverlay ) 63 | { 64 | if ( webResources != null ) 65 | { 66 | this.webResources = webResources; 67 | } 68 | else 69 | { 70 | this.webResources = new Resource[0]; 71 | } 72 | this.webXml = webXml; 73 | this.containerConfigXML = containerConfigXml; 74 | this.currentProjectOverlay = currentProjectOverlay; 75 | this.id = currentProjectOverlay.getId(); 76 | } 77 | 78 | /** 79 | * {@inheritDoc} 80 | */ 81 | public void performPackaging( WarPackagingContext context ) 82 | throws MojoExecutionException, MojoFailureException 83 | { 84 | 85 | context.getLog().info( "Processing war project" ); 86 | // Prepare the INF directories 87 | File webinfDir = new File( context.getWebappDirectory(), WEB_INF_PATH ); 88 | webinfDir.mkdirs(); 89 | File metainfDir = new File( context.getWebappDirectory(), META_INF_PATH ); 90 | metainfDir.mkdirs(); 91 | 92 | handleWebResources( context ); 93 | 94 | handeWebAppSourceDirectory( context ); 95 | 96 | // Debug mode: dump the path set for the current build 97 | PathSet pathSet = context.getWebappStructure().getStructure( "currentBuild" ); 98 | context.getLog().debug( "Dump of the current build pathSet content -->" ); 99 | for ( String path : pathSet ) 100 | { 101 | context.getLog().debug( path ); 102 | } 103 | context.getLog().debug( "-- end of dump --" ); 104 | 105 | handleDeploymentDescriptors( context, webinfDir, metainfDir ); 106 | 107 | handleClassesDirectory( context ); 108 | 109 | handleArtifacts( context ); 110 | } 111 | 112 | /** 113 | * Handles the web resources. 114 | * 115 | * @param context the packaging context 116 | * @throws MojoExecutionException if a resource could not be copied 117 | */ 118 | protected void handleWebResources( WarPackagingContext context ) 119 | throws MojoExecutionException 120 | { 121 | for ( Resource resource : webResources ) 122 | { 123 | 124 | // MWAR-246 125 | if ( resource.getDirectory() == null ) 126 | { 127 | throw new MojoExecutionException( "The tag is missing from the tag." ); 128 | } 129 | 130 | if ( !( new File( resource.getDirectory() ) ).isAbsolute() ) 131 | { 132 | resource.setDirectory( context.getProject().getBasedir() + File.separator + resource.getDirectory() ); 133 | } 134 | 135 | // Make sure that the resource directory is not the same as the webappDirectory 136 | if ( !resource.getDirectory().equals( context.getWebappDirectory().getPath() ) ) 137 | { 138 | 139 | try 140 | { 141 | copyResources( context, resource ); 142 | } 143 | catch ( IOException e ) 144 | { 145 | throw new MojoExecutionException( "Could not copy resource [" + resource.getDirectory() + "]", e ); 146 | } 147 | } 148 | } 149 | } 150 | 151 | /** 152 | * Handles the webapp sources. 153 | * 154 | * @param context the packaging context 155 | * @throws MojoExecutionException if the sources could not be copied 156 | */ 157 | protected void handeWebAppSourceDirectory( WarPackagingContext context ) 158 | throws MojoExecutionException 159 | { 160 | // CHECKSTYLE_OFF: LineLength 161 | if ( !context.getWebappSourceDirectory().exists() ) 162 | { 163 | context.getLog().debug( "webapp sources directory does not exist - skipping." ); 164 | } 165 | else if ( !context.getWebappSourceDirectory().getAbsolutePath().equals( context.getWebappDirectory().getPath() ) ) 166 | { 167 | context.getLog().info( "Copying webapp resources [" + context.getWebappSourceDirectory() + "]" ); 168 | final PathSet sources = 169 | getFilesToIncludes( context.getWebappSourceDirectory(), context.getWebappSourceIncludes(), 170 | context.getWebappSourceExcludes(), context.isWebappSourceIncludeEmptyDirectories() ); 171 | 172 | try 173 | { 174 | copyFiles( id, context, context.getWebappSourceDirectory(), sources, false ); 175 | } 176 | catch ( IOException e ) 177 | { 178 | throw new MojoExecutionException( "Could not copy webapp sources [" 179 | + context.getWebappDirectory().getAbsolutePath() + "]", e ); 180 | } 181 | } 182 | // CHECKSTYLE_ON: LineLength 183 | } 184 | 185 | /** 186 | * Handles the webapp artifacts. 187 | * 188 | * @param context the packaging context 189 | * @throws MojoExecutionException if the artifacts could not be packaged 190 | */ 191 | protected void handleArtifacts( WarPackagingContext context ) 192 | throws MojoExecutionException 193 | { 194 | @SuppressWarnings( "unchecked" ) 195 | ArtifactsPackagingTask task = 196 | new ArtifactsPackagingTask( context.getProject().getArtifacts(), currentProjectOverlay ); 197 | task.performPackaging( context ); 198 | } 199 | 200 | /** 201 | * Handles the webapp classes. 202 | * 203 | * @param context the packaging context 204 | * @throws MojoExecutionException if the classes could not be packaged 205 | */ 206 | protected void handleClassesDirectory( WarPackagingContext context ) 207 | throws MojoExecutionException 208 | { 209 | ClassesPackagingTask task = new ClassesPackagingTask( currentProjectOverlay ); 210 | task.performPackaging( context ); 211 | } 212 | 213 | /** 214 | * Handles the deployment descriptors, if specified. Note that the behavior here is slightly different since the 215 | * customized entry always win, even if an overlay has already packaged a web.xml previously. 216 | * 217 | * @param context the packaging context 218 | * @param webinfDir the web-inf directory 219 | * @param metainfDir the meta-inf directory 220 | * @throws MojoFailureException if the web.xml is specified but does not exist 221 | * @throws MojoExecutionException if an error occurred while copying the descriptors 222 | */ 223 | protected void handleDeploymentDescriptors( WarPackagingContext context, File webinfDir, File metainfDir ) 224 | throws MojoFailureException, MojoExecutionException 225 | { 226 | try 227 | { 228 | if ( webXml != null && StringUtils.isNotEmpty( webXml.getName() ) ) 229 | { 230 | if ( !webXml.exists() ) 231 | { 232 | throw new MojoFailureException( "The specified web.xml file '" + webXml + "' does not exist" ); 233 | } 234 | 235 | // Making sure that it won't get overlayed 236 | context.getWebappStructure().registerFileForced( id, WEB_INF_PATH + "/web.xml" ); 237 | 238 | if ( context.isFilteringDeploymentDescriptors() ) 239 | { 240 | context.getMavenFileFilter().copyFile( webXml, new File( webinfDir, "web.xml" ), true, 241 | context.getFilterWrappers(), getEncoding( webXml ) ); 242 | } 243 | else 244 | { 245 | copyFile( context, webXml, new File( webinfDir, "web.xml" ), "WEB-INF/web.xml", true ); 246 | } 247 | } 248 | else 249 | { 250 | // the webXml can be the default one 251 | File defaultWebXml = new File( context.getWebappSourceDirectory(), WEB_INF_PATH + "/web.xml" ); 252 | // if exists we can filter it 253 | if ( defaultWebXml.exists() && context.isFilteringDeploymentDescriptors() ) 254 | { 255 | context.getWebappStructure().registerFile( id, WEB_INF_PATH + "/web.xml" ); 256 | context.getMavenFileFilter().copyFile( defaultWebXml, new File( webinfDir, "web.xml" ), true, 257 | context.getFilterWrappers(), getEncoding( defaultWebXml ) ); 258 | } 259 | } 260 | 261 | if ( containerConfigXML != null && StringUtils.isNotEmpty( containerConfigXML.getName() ) ) 262 | { 263 | String xmlFileName = containerConfigXML.getName(); 264 | 265 | context.getWebappStructure().registerFileForced( id, META_INF_PATH + "/" + xmlFileName ); 266 | 267 | if ( context.isFilteringDeploymentDescriptors() ) 268 | { 269 | context.getMavenFileFilter().copyFile( containerConfigXML, new File( metainfDir, xmlFileName ), 270 | true, context.getFilterWrappers(), 271 | getEncoding( containerConfigXML ) ); 272 | } 273 | else 274 | { 275 | copyFile( context, containerConfigXML, new File( metainfDir, xmlFileName ), "META-INF/" 276 | + xmlFileName, true ); 277 | } 278 | } 279 | } 280 | catch ( IOException e ) 281 | { 282 | throw new MojoExecutionException( "Failed to copy deployment descriptor", e ); 283 | } 284 | catch ( MavenFilteringException e ) 285 | { 286 | throw new MojoExecutionException( "Failed to copy deployment descriptor", e ); 287 | } 288 | } 289 | 290 | /** 291 | * Copies webapp webResources from the specified directory. 292 | * 293 | * @param context the WAR packaging context to use 294 | * @param resource the resource to copy 295 | * @throws IOException if an error occurred while copying the resources 296 | * @throws MojoExecutionException if an error occurred while retrieving the filter properties 297 | */ 298 | public void copyResources( WarPackagingContext context, Resource resource ) 299 | throws IOException, MojoExecutionException 300 | { 301 | if ( !context.getWebappDirectory().exists() ) 302 | { 303 | context.getLog().warn( "Not copying webapp webResources [" + resource.getDirectory() 304 | + "]: webapp directory [" + context.getWebappDirectory().getAbsolutePath() 305 | + "] does not exist!" ); 306 | } 307 | 308 | context.getLog().info( "Copying webapp webResources [" + resource.getDirectory() + "] to [" 309 | + context.getWebappDirectory().getAbsolutePath() + "]" ); 310 | String[] fileNames = getFilesToCopy( resource ); 311 | for ( String fileName : fileNames ) 312 | { 313 | String targetFileName = fileName; 314 | if ( resource.getTargetPath() != null ) 315 | { 316 | // TODO make sure this thing is 100% safe 317 | // MWAR-129 if targetPath is only a dot . or ./ 318 | // and the Resource is in a part of the warSourceDirectory the file from sources will override this 319 | // that's we don't have to add the targetPath yep not nice but works 320 | if ( !StringUtils.equals( ".", resource.getTargetPath() ) 321 | && !StringUtils.equals( "./", resource.getTargetPath() ) ) 322 | { 323 | targetFileName = resource.getTargetPath() + File.separator + targetFileName; 324 | } 325 | } 326 | if ( resource.isFiltering() && !context.isNonFilteredExtension( fileName ) ) 327 | { 328 | copyFilteredFile( id, context, new File( resource.getDirectory(), fileName ), targetFileName ); 329 | } 330 | else 331 | { 332 | copyFile( id, context, new File( resource.getDirectory(), fileName ), targetFileName ); 333 | } 334 | } 335 | } 336 | 337 | /** 338 | * Returns a list of filenames that should be copied over to the destination directory. 339 | * 340 | * @param resource the resource to be scanned 341 | * @return the array of filenames, relative to the sourceDir 342 | */ 343 | private String[] getFilesToCopy( Resource resource ) 344 | { 345 | // CHECKSTYLE_OFF: LineLength 346 | DirectoryScanner scanner = new DirectoryScanner(); 347 | scanner.setBasedir( resource.getDirectory() ); 348 | if ( resource.getIncludes() != null && !resource.getIncludes().isEmpty() ) 349 | { 350 | scanner.setIncludes( (String[]) resource.getIncludes().toArray( new String[resource.getIncludes().size()] ) ); 351 | } 352 | else 353 | { 354 | scanner.setIncludes( DEFAULT_INCLUDES ); 355 | } 356 | if ( resource.getExcludes() != null && !resource.getExcludes().isEmpty() ) 357 | { 358 | scanner.setExcludes( (String[]) resource.getExcludes().toArray( new String[resource.getExcludes().size()] ) ); 359 | } 360 | 361 | scanner.addDefaultExcludes(); 362 | 363 | scanner.scan(); 364 | 365 | return scanner.getIncludedFiles(); 366 | // CHECKSTYLE_ON: LineLength 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/packaging/AbstractWarPackagingTask.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.packaging; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | 25 | import cn.wanghaomiao.maven.plugin.seimi.util.PathSet; 26 | import org.apache.commons.io.input.XmlStreamReader; 27 | import org.apache.maven.artifact.Artifact; 28 | import org.apache.maven.plugin.MojoExecutionException; 29 | import cn.wanghaomiao.maven.plugin.seimi.util.WebappStructure; 30 | import org.apache.maven.shared.filtering.MavenFilteringException; 31 | import org.apache.maven.shared.mapping.MappingUtils; 32 | import org.codehaus.plexus.archiver.ArchiverException; 33 | import org.codehaus.plexus.archiver.UnArchiver; 34 | import org.codehaus.plexus.archiver.jar.JarArchiver; 35 | import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; 36 | import org.codehaus.plexus.interpolation.InterpolationException; 37 | import org.codehaus.plexus.util.DirectoryScanner; 38 | import org.codehaus.plexus.util.FileUtils; 39 | import org.codehaus.plexus.util.IOUtil; 40 | 41 | /** 42 | * @author Stephane Nicoll 43 | * @version $Id: AbstractWarPackagingTask.java 1637197 2014-11-06 19:46:57Z khmarbaise $ 44 | */ 45 | public abstract class AbstractWarPackagingTask 46 | implements WarPackagingTask 47 | { 48 | /** 49 | * The default list of includes. 50 | */ 51 | public static final String[] DEFAULT_INCLUDES = { "**/**" }; 52 | 53 | /** 54 | * The {@code WEB-INF} path. 55 | */ 56 | public static final String WEB_INF_PATH = "seimi"; 57 | 58 | /** 59 | * The {@code META-INF} path. 60 | */ 61 | public static final String META_INF_PATH = "seimi"; 62 | 63 | /** 64 | * The {@code classes} path. 65 | */ 66 | public static final String CLASSES_PATH = "seimi/classes/"; 67 | 68 | /** 69 | * The {@code lib} path. 70 | */ 71 | public static final String LIB_PATH = "seimi/lib/"; 72 | 73 | /** 74 | * Copies the files if possible with an optional target prefix. 75 | *

76 | * Copy uses a first-win strategy: files that have already been copied by previous tasks are ignored. This method 77 | * makes sure to update the list of protected files which gives the list of files that have already been copied. 78 | *

79 | * If the structure of the source directory is not the same as the root of the webapp, use the targetPrefix 80 | * parameter to specify in which particular directory the files should be copied. Use null to copy the 81 | * files with the same structure 82 | * 83 | * @param sourceId the source id 84 | * @param context the context to use 85 | * @param sourceBaseDir the base directory from which the sourceFilesSet will be copied 86 | * @param sourceFilesSet the files to be copied 87 | * @param targetPrefix the prefix to add to the target file name 88 | * @param filtered filter or not. 89 | * @throws IOException if an error occurred while copying the files 90 | * @throws MojoExecutionException if an error occurs. 91 | */ 92 | protected void copyFiles( String sourceId, WarPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet, 93 | String targetPrefix, boolean filtered ) 94 | throws IOException, MojoExecutionException 95 | { 96 | for ( String fileToCopyName : sourceFilesSet.paths() ) 97 | { 98 | final File sourceFile = new File( sourceBaseDir, fileToCopyName ); 99 | 100 | String destinationFileName; 101 | if ( targetPrefix == null ) 102 | { 103 | destinationFileName = fileToCopyName; 104 | } 105 | else 106 | { 107 | destinationFileName = targetPrefix + fileToCopyName; 108 | } 109 | 110 | if ( filtered && !context.isNonFilteredExtension( sourceFile.getName() ) ) 111 | { 112 | copyFilteredFile( sourceId, context, sourceFile, destinationFileName ); 113 | } 114 | else 115 | { 116 | copyFile( sourceId, context, sourceFile, destinationFileName ); 117 | } 118 | } 119 | } 120 | 121 | /** 122 | * Copies the files if possible as is. 123 | *

124 | * Copy uses a first-win strategy: files that have already been copied by previous tasks are ignored. This method 125 | * makes sure to update the list of protected files which gives the list of files that have already been copied. 126 | * 127 | * @param sourceId the source id 128 | * @param context the context to use 129 | * @param sourceBaseDir the base directory from which the sourceFilesSet will be copied 130 | * @param sourceFilesSet the files to be copied 131 | * @param filtered filter or not. 132 | * @throws IOException if an error occurred while copying the files 133 | * @throws MojoExecutionException break the build. 134 | */ 135 | protected void copyFiles( String sourceId, WarPackagingContext context, File sourceBaseDir, PathSet sourceFilesSet, 136 | boolean filtered ) 137 | throws IOException, MojoExecutionException 138 | { 139 | copyFiles( sourceId, context, sourceBaseDir, sourceFilesSet, null, filtered ); 140 | } 141 | 142 | /** 143 | * Copy the specified file if the target location has not yet already been used. 144 | *

145 | * The targetFileName is the relative path according to the root of the generated web application. 146 | * 147 | * @param sourceId the source id 148 | * @param context the context to use 149 | * @param file the file to copy 150 | * @param targetFilename the relative path according to the root of the webapp 151 | * @throws IOException if an error occurred while copying 152 | */ 153 | // CHECKSTYLE_OFF: LineLength 154 | protected void copyFile( String sourceId, final WarPackagingContext context, final File file, String targetFilename ) 155 | throws IOException 156 | // CHECKSTYLE_ON: LineLength 157 | { 158 | final File targetFile = new File( context.getWebappDirectory(), targetFilename ); 159 | 160 | if ( file.isFile() ) 161 | { 162 | context.getWebappStructure().registerFile( sourceId, targetFilename, 163 | new WebappStructure.RegistrationCallback() 164 | { 165 | public void registered( String ownerId, String targetFilename ) 166 | throws IOException 167 | { 168 | copyFile( context, file, targetFile, targetFilename, 169 | false ); 170 | } 171 | 172 | public void alreadyRegistered( String ownerId, 173 | String targetFilename ) 174 | throws IOException 175 | { 176 | copyFile( context, file, targetFile, targetFilename, 177 | true ); 178 | } 179 | 180 | public void refused( String ownerId, String targetFilename, 181 | String actualOwnerId ) 182 | throws IOException 183 | { 184 | context.getLog().debug( " - " 185 | + targetFilename 186 | + " wasn't copied because it has " 187 | + "already been packaged for overlay [" 188 | + actualOwnerId + "]." ); 189 | } 190 | 191 | public void superseded( String ownerId, 192 | String targetFilename, 193 | String deprecatedOwnerId ) 194 | throws IOException 195 | { 196 | context.getLog().info( "File [" 197 | + targetFilename 198 | + "] belonged to overlay [" 199 | + deprecatedOwnerId 200 | + "] so it will be overwritten." ); 201 | copyFile( context, file, targetFile, targetFilename, 202 | false ); 203 | } 204 | 205 | public void supersededUnknownOwner( String ownerId, 206 | String targetFilename, 207 | String unknownOwnerId ) 208 | throws IOException 209 | { 210 | // CHECKSTYLE_OFF: LineLength 211 | context.getLog().warn( "File [" 212 | + targetFilename 213 | + "] belonged to overlay [" 214 | + unknownOwnerId 215 | + "] which does not exist anymore in the current project. It is recommended to invoke " 216 | + "clean if the dependencies of the project changed." ); 217 | // CHECKSTYLE_ON: LineLength 218 | copyFile( context, file, targetFile, targetFilename, 219 | false ); 220 | } 221 | } ); 222 | } 223 | else if ( !targetFile.exists() && !targetFile.mkdirs() ) 224 | { 225 | context.getLog().info( "Failed to create directory " + targetFile.getAbsolutePath() ); 226 | } 227 | } 228 | 229 | /** 230 | * Copy the specified file if the target location has not yet already been used and filter its content with the 231 | * configured filter properties. 232 | *

233 | * The targetFileName is the relative path according to the root of the generated web application. 234 | * 235 | * @param sourceId the source id 236 | * @param context the context to use 237 | * @param file the file to copy 238 | * @param targetFilename the relative path according to the root of the webapp 239 | * @return true if the file has been copied, false otherwise 240 | * @throws IOException if an error occurred while copying 241 | * @throws MojoExecutionException if an error occurred while retrieving the filter properties 242 | */ 243 | protected boolean copyFilteredFile( String sourceId, final WarPackagingContext context, File file, 244 | String targetFilename ) 245 | throws IOException, MojoExecutionException 246 | { 247 | 248 | if ( context.getWebappStructure().registerFile( sourceId, targetFilename ) ) 249 | { 250 | final File targetFile = new File( context.getWebappDirectory(), targetFilename ); 251 | final String encoding; 252 | try 253 | { 254 | if ( isXmlFile( file ) ) 255 | { 256 | // For xml-files we extract the encoding from the files 257 | encoding = getEncoding( file ); 258 | } 259 | else 260 | { 261 | // For all others we use the configured encoding 262 | encoding = context.getResourceEncoding(); 263 | } 264 | // fix for MWAR-36, ensures that the parent dir are created first 265 | targetFile.getParentFile().mkdirs(); 266 | 267 | context.getMavenFileFilter().copyFile( file, targetFile, true, context.getFilterWrappers(), encoding ); 268 | } 269 | catch ( MavenFilteringException e ) 270 | { 271 | throw new MojoExecutionException( e.getMessage(), e ); 272 | } 273 | // CHECKSTYLE_OFF: LineLength 274 | // Add the file to the protected list 275 | context.getLog().debug( " + " + targetFilename + " has been copied (filtered encoding='" + encoding + "')." ); 276 | // CHECKSTYLE_ON: LineLength 277 | return true; 278 | } 279 | else 280 | { 281 | context.getLog().debug( " - " + targetFilename 282 | + " wasn't copied because it has already been packaged (filtered)." ); 283 | return false; 284 | } 285 | } 286 | 287 | /** 288 | * Unpacks the specified file to the specified directory. 289 | * 290 | * @param context the packaging context 291 | * @param file the file to unpack 292 | * @param unpackDirectory the directory to use for th unpacked file 293 | * @throws MojoExecutionException if an error occurred while unpacking the file 294 | */ 295 | protected void doUnpack( WarPackagingContext context, File file, File unpackDirectory ) 296 | throws MojoExecutionException 297 | { 298 | String archiveExt = FileUtils.getExtension( file.getAbsolutePath() ).toLowerCase(); 299 | 300 | try 301 | { 302 | UnArchiver unArchiver = context.getArchiverManager().getUnArchiver( archiveExt ); 303 | unArchiver.setSourceFile( file ); 304 | unArchiver.setUseJvmChmod( context.isUseJvmChmod() ); 305 | unArchiver.setDestDirectory( unpackDirectory ); 306 | unArchiver.setOverwrite( true ); 307 | unArchiver.extract(); 308 | } 309 | catch ( ArchiverException e ) 310 | { 311 | throw new MojoExecutionException( "Error unpacking file [" + file.getAbsolutePath() + "]" + "to [" 312 | + unpackDirectory.getAbsolutePath() + "]", e ); 313 | } 314 | catch ( NoSuchArchiverException e ) 315 | { 316 | context.getLog().warn( "Skip unpacking dependency file [" + file.getAbsolutePath() 317 | + " with unknown extension [" + archiveExt + "]" ); 318 | } 319 | } 320 | 321 | /** 322 | * Copy file from source to destination. The directories up to destination will be created if they 323 | * don't already exist. if the onlyIfModified flag is false, destination will be 324 | * overwritten if it already exists. If the flag is true destination will be overwritten if it's not up to 325 | * date. 326 | *

327 | * 328 | * @param context the packaging context 329 | * @param source an existing non-directory File to copy bytes from 330 | * @param destination a non-directory File to write bytes to (possibly overwriting). 331 | * @param targetFilename the relative path of the file from the webapp root directory 332 | * @param onlyIfModified if true, copy the file only if the source has changed, always copy otherwise 333 | * @return true if the file has been copied/updated, false otherwise 334 | * @throws IOException if source does not exist, destination cannot be written to, or an 335 | * IO error occurs during copying 336 | */ 337 | protected boolean copyFile( WarPackagingContext context, File source, File destination, String targetFilename, 338 | boolean onlyIfModified ) 339 | throws IOException 340 | { 341 | if ( onlyIfModified && destination.lastModified() >= source.lastModified() ) 342 | { 343 | context.getLog().debug( " * " + targetFilename + " is up to date." ); 344 | return false; 345 | } 346 | else 347 | { 348 | if ( source.isDirectory() ) 349 | { 350 | context.getLog().warn( " + " + targetFilename + " is packaged from the source folder" ); 351 | 352 | try 353 | { 354 | JarArchiver archiver = context.getJarArchiver(); 355 | archiver.addDirectory( source ); 356 | archiver.setDestFile( destination ); 357 | archiver.createArchive(); 358 | } 359 | catch ( ArchiverException e ) 360 | { 361 | String msg = "Failed to create " + targetFilename; 362 | context.getLog().error( msg, e ); 363 | IOException ioe = new IOException( msg ); 364 | ioe.initCause( e ); 365 | throw ioe; 366 | } 367 | } 368 | else 369 | { 370 | FileUtils.copyFile( source.getCanonicalFile(), destination ); 371 | // preserve timestamp 372 | destination.setLastModified( source.lastModified() ); 373 | context.getLog().debug( " + " + targetFilename + " has been copied." ); 374 | } 375 | return true; 376 | } 377 | } 378 | 379 | /** 380 | * Get the encoding from an XML-file. 381 | * 382 | * @param webXml the XML-file 383 | * @return The encoding of the XML-file, or UTF-8 if it's not specified in the file 384 | * @throws java.io.IOException if an error occurred while reading the file 385 | */ 386 | protected String getEncoding( File webXml ) 387 | throws IOException 388 | { 389 | XmlStreamReader xmlReader = new XmlStreamReader( webXml ); 390 | try 391 | { 392 | return xmlReader.getEncoding(); 393 | } 394 | finally 395 | { 396 | IOUtil.close( xmlReader ); 397 | } 398 | } 399 | 400 | /** 401 | * Returns the file to copy. If the includes are null or empty, the default includes are used. 402 | * 403 | * @param baseDir the base directory to start from 404 | * @param includes the includes 405 | * @param excludes the excludes 406 | * @return the files to copy 407 | */ 408 | protected PathSet getFilesToIncludes( File baseDir, String[] includes, String[] excludes ) 409 | { 410 | return getFilesToIncludes( baseDir, includes, excludes, false ); 411 | } 412 | 413 | /** 414 | * Returns the file to copy. If the includes are null or empty, the default includes are used. 415 | * 416 | * @param baseDir the base directory to start from 417 | * @param includes the includes 418 | * @param excludes the excludes 419 | * @param includeDirectories include directories yes or not. 420 | * @return the files to copy 421 | */ 422 | // CHECKSTYLE_OFF: LineLength 423 | protected PathSet getFilesToIncludes( File baseDir, String[] includes, String[] excludes, boolean includeDirectories ) 424 | // CHECKSTYLE_ON: LineLength 425 | { 426 | final DirectoryScanner scanner = new DirectoryScanner(); 427 | scanner.setBasedir( baseDir ); 428 | 429 | if ( excludes != null ) 430 | { 431 | scanner.setExcludes( excludes ); 432 | } 433 | scanner.addDefaultExcludes(); 434 | 435 | if ( includes != null && includes.length > 0 ) 436 | { 437 | scanner.setIncludes( includes ); 438 | } 439 | else 440 | { 441 | scanner.setIncludes( DEFAULT_INCLUDES ); 442 | } 443 | 444 | scanner.scan(); 445 | 446 | PathSet pathSet = new PathSet( scanner.getIncludedFiles() ); 447 | 448 | if ( includeDirectories ) 449 | { 450 | pathSet.addAll( scanner.getIncludedDirectories() ); 451 | } 452 | 453 | return pathSet; 454 | } 455 | 456 | /** 457 | * Returns the final name of the specified artifact. 458 | *

459 | * If the outputFileNameMapping is set, it is used, otherwise the standard naming scheme is used. 460 | * 461 | * @param context the packaging context 462 | * @param artifact the artifact 463 | * @return the converted filename of the artifact 464 | * @throws InterpolationException in case of interpolation problem. 465 | */ 466 | protected String getArtifactFinalName( WarPackagingContext context, Artifact artifact ) 467 | throws InterpolationException 468 | { 469 | if ( context.getOutputFileNameMapping() != null ) 470 | { 471 | return MappingUtils.evaluateFileNameMapping( context.getOutputFileNameMapping(), artifact ); 472 | } 473 | 474 | String classifier = artifact.getClassifier(); 475 | if ( ( classifier != null ) && !( "".equals( classifier.trim() ) ) ) 476 | { 477 | return MappingUtils.evaluateFileNameMapping( MappingUtils.DEFAULT_FILE_NAME_MAPPING_CLASSIFIER, artifact ); 478 | } 479 | else 480 | { 481 | return MappingUtils.evaluateFileNameMapping( MappingUtils.DEFAULT_FILE_NAME_MAPPING, artifact ); 482 | } 483 | 484 | } 485 | 486 | /** 487 | * Returns true if the File-object is a file (not a directory) that is not 488 | * null and has a file name that ends in ".xml". 489 | * 490 | * @param file The file to check 491 | * @return true if the file is an xml-file, otherwise false 492 | * @since 2.3 493 | */ 494 | private boolean isXmlFile( File file ) 495 | { 496 | return file != null && file.isFile() && file.getName().endsWith( ".xml" ); 497 | } 498 | } 499 | -------------------------------------------------------------------------------- /src/main/java/cn/wanghaomiao/maven/plugin/seimi/util/WebappStructure.java: -------------------------------------------------------------------------------- 1 | package cn.wanghaomiao.maven.plugin.seimi.util; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.apache.maven.artifact.Artifact; 23 | import org.apache.maven.model.Dependency; 24 | import org.codehaus.plexus.util.StringUtils; 25 | 26 | import java.io.IOException; 27 | import java.util.ArrayList; 28 | import java.util.Collections; 29 | import java.util.HashMap; 30 | import java.util.Iterator; 31 | import java.util.List; 32 | import java.util.Map; 33 | import java.util.Set; 34 | 35 | /** 36 | * Represents the structure of a web application composed of multiple overlays. Each overlay is registered within this 37 | * structure with the set of files it holds. 38 | *

39 | * Note that this structure is persisted to disk at each invocation to store which owner holds which path (file). 40 | * 41 | * @author Stephane Nicoll 42 | * @version $Id: WebappStructure.java 1636820 2014-11-05 08:27:25Z khmarbaise $ 43 | */ 44 | public class WebappStructure 45 | { 46 | 47 | private Map registeredFiles; 48 | 49 | private List dependenciesInfo; 50 | 51 | private transient PathSet allFiles = new PathSet(); 52 | 53 | private transient WebappStructure cache; 54 | 55 | /** 56 | * Creates a new empty instance. 57 | * 58 | * @param dependencies the dependencies of the project 59 | */ 60 | public WebappStructure( List dependencies ) 61 | { 62 | this.dependenciesInfo = createDependenciesInfoList( dependencies ); 63 | this.registeredFiles = new HashMap(); 64 | this.cache = null; 65 | } 66 | 67 | /** 68 | * Creates a new instance with the specified cache. 69 | * 70 | * @param dependencies the dependencies of the project 71 | * @param cache the cache 72 | */ 73 | public WebappStructure( List dependencies, WebappStructure cache ) 74 | { 75 | this.dependenciesInfo = createDependenciesInfoList( dependencies ); 76 | this.registeredFiles = new HashMap(); 77 | if ( cache == null ) 78 | { 79 | this.cache = new WebappStructure( dependencies ); 80 | } 81 | else 82 | { 83 | this.cache = cache; 84 | } 85 | } 86 | 87 | /** 88 | * Returns the list of {@link DependencyInfo} for the project. 89 | * 90 | * @return the dependencies information of the project 91 | */ 92 | public List getDependenciesInfo() 93 | { 94 | return dependenciesInfo; 95 | } 96 | 97 | /** 98 | * Returns the dependencies of the project. 99 | * 100 | * @return the dependencies of the project 101 | */ 102 | public List getDependencies() 103 | { 104 | final List result = new ArrayList(); 105 | if ( dependenciesInfo == null ) 106 | { 107 | return result; 108 | } 109 | for ( DependencyInfo dependencyInfo : dependenciesInfo ) 110 | { 111 | result.add( dependencyInfo.getDependency() ); 112 | } 113 | return result; 114 | } 115 | 116 | /** 117 | * Specify if the specified path is registered or not. 118 | * 119 | * @param path the relative path from the webapp root directory 120 | * @return true if the path is registered, false otherwise 121 | */ 122 | public boolean isRegistered( String path ) 123 | { 124 | return getFullStructure().contains( path ); 125 | 126 | } 127 | 128 | /** 129 | * Registers the specified path for the specified owner. Returns true if the path is not already 130 | * registered, false otherwise. 131 | * 132 | * @param id the owner of the path 133 | * @param path the relative path from the webapp root directory 134 | * @return true if the file was registered successfully 135 | */ 136 | public boolean registerFile( String id, String path ) 137 | { 138 | if ( !isRegistered( path ) ) 139 | { 140 | doRegister( id, path ); 141 | return true; 142 | } 143 | else 144 | { 145 | return false; 146 | } 147 | } 148 | 149 | /** 150 | * Forces the registration of the specified path for the specified owner. If the file is not registered yet, a 151 | * simple registration is performed. If the file already exists, the owner changes to the specified one. 152 | *

153 | * Beware that the semantic of the return boolean is different than the one from 154 | * {@link #registerFile(String, String)}; returns true if an owner replacement was made and false 155 | * if the file was simply registered for the first time. 156 | * 157 | * @param id the owner of the path 158 | * @param path the relative path from the webapp root directory 159 | * @return false if the file did not exist, true if the owner was replaced 160 | */ 161 | public boolean registerFileForced( String id, String path ) 162 | { 163 | if ( !isRegistered( path ) ) 164 | { 165 | doRegister( id, path ); 166 | return false; 167 | } 168 | else 169 | { 170 | // Force the switch to the new owner 171 | getStructure( getOwner( path ) ).remove( path ); 172 | getStructure( id ).add( path ); 173 | return true; 174 | } 175 | 176 | } 177 | 178 | /** 179 | * Registers the specified path for the specified owner. Invokes the callback with the result of the 180 | * registration. 181 | * 182 | * @param id the owner of the path 183 | * @param path the relative path from the webapp root directory 184 | * @param callback the callback to invoke with the result of the registration 185 | * @throws IOException if the callback invocation throws an IOException 186 | */ 187 | public void registerFile( String id, String path, RegistrationCallback callback ) 188 | throws IOException 189 | { 190 | 191 | // If the file is already in the current structure, rejects it with the current owner 192 | if ( isRegistered( path ) ) 193 | { 194 | callback.refused( id, path, getOwner( path ) ); 195 | } 196 | else 197 | { 198 | doRegister( id, path ); 199 | // This is a new file 200 | if ( cache.getOwner( path ) == null ) 201 | { 202 | callback.registered( id, path ); 203 | 204 | } // The file already belonged to this owner 205 | else if ( cache.getOwner( path ).equals( id ) ) 206 | { 207 | callback.alreadyRegistered( id, path ); 208 | } // The file belongs to another owner and it's known currently 209 | else if ( getOwners().contains( cache.getOwner( path ) ) ) 210 | { 211 | callback.superseded( id, path, cache.getOwner( path ) ); 212 | } // The file belongs to another owner and it's unknown 213 | else 214 | { 215 | callback.supersededUnknownOwner( id, path, cache.getOwner( path ) ); 216 | } 217 | } 218 | } 219 | 220 | /** 221 | * Returns the owner of the specified path. If the file is not registered, returns null 222 | * 223 | * @param path the relative path from the webapp root directory 224 | * @return the owner or null. 225 | */ 226 | public String getOwner( String path ) 227 | { 228 | if ( !isRegistered( path ) ) 229 | { 230 | return null; 231 | } 232 | else 233 | { 234 | for ( final String owner : registeredFiles.keySet() ) 235 | { 236 | final PathSet structure = getStructure( owner ); 237 | if ( structure.contains( path ) ) 238 | { 239 | return owner; 240 | } 241 | 242 | } 243 | throw new IllegalStateException( "Should not happen, path [" + path 244 | + "] is flagged as being registered but was not found." ); 245 | } 246 | 247 | } 248 | 249 | /** 250 | * Returns the owners. Note that this the returned {@link Set} may be inconsistent since it represents a persistent 251 | * cache across multiple invocations. 252 | *

253 | * For instance, if an overlay was removed in this execution, it will be still be there till the cache is cleaned. 254 | * This happens when the clean mojo is invoked. 255 | * 256 | * @return the list of owners 257 | */ 258 | public Set getOwners() 259 | { 260 | return registeredFiles.keySet(); 261 | } 262 | 263 | /** 264 | * Returns all paths that have been registered so far. 265 | * 266 | * @return all registered path 267 | */ 268 | public PathSet getFullStructure() 269 | { 270 | return allFiles; 271 | } 272 | 273 | /** 274 | * Returns the list of registered files for the specified owner. 275 | * 276 | * @param id the owner 277 | * @return the list of files registered for that owner 278 | */ 279 | public PathSet getStructure( String id ) 280 | { 281 | PathSet pathSet = registeredFiles.get( id ); 282 | if ( pathSet == null ) 283 | { 284 | pathSet = new PathSet(); 285 | registeredFiles.put( id, pathSet ); 286 | } 287 | return pathSet; 288 | } 289 | 290 | /** 291 | * Analyze the dependencies of the project using the specified callback. 292 | * 293 | * @param callback the callback to use to report the result of the analysis 294 | */ 295 | public void analyseDependencies( DependenciesAnalysisCallback callback ) 296 | { 297 | if ( callback == null ) 298 | { 299 | throw new NullPointerException( "Callback could not be null." ); 300 | } 301 | if ( cache == null ) 302 | { 303 | // Could not analyze dependencies without a cache 304 | return; 305 | } 306 | 307 | final List currentDependencies = new ArrayList( getDependencies() ); 308 | final List previousDependencies = new ArrayList( cache.getDependencies() ); 309 | final Iterator it = currentDependencies.listIterator(); 310 | while ( it.hasNext() ) 311 | { 312 | Dependency dependency = it.next(); 313 | // Check if the dependency is there "as is" 314 | 315 | final Dependency matchingDependency = matchDependency( previousDependencies, dependency ); 316 | if ( matchingDependency != null ) 317 | { 318 | callback.unchangedDependency( dependency ); 319 | // Handled so let's remove 320 | it.remove(); 321 | previousDependencies.remove( matchingDependency ); 322 | } 323 | else 324 | { 325 | // Try to get the dependency 326 | final Dependency previousDep = findDependency( dependency, previousDependencies ); 327 | if ( previousDep == null ) 328 | { 329 | callback.newDependency( dependency ); 330 | it.remove(); 331 | } 332 | else if ( !dependency.getVersion().equals( previousDep.getVersion() ) ) 333 | { 334 | callback.updatedVersion( dependency, previousDep.getVersion() ); 335 | it.remove(); 336 | previousDependencies.remove( previousDep ); 337 | } 338 | else if ( !dependency.getScope().equals( previousDep.getScope() ) ) 339 | { 340 | callback.updatedScope( dependency, previousDep.getScope() ); 341 | it.remove(); 342 | previousDependencies.remove( previousDep ); 343 | } 344 | else if ( dependency.isOptional() != previousDep.isOptional() ) 345 | { 346 | callback.updatedOptionalFlag( dependency, previousDep.isOptional() ); 347 | it.remove(); 348 | previousDependencies.remove( previousDep ); 349 | } 350 | else 351 | { 352 | callback.updatedUnknown( dependency, previousDep ); 353 | it.remove(); 354 | previousDependencies.remove( previousDep ); 355 | } 356 | } 357 | } 358 | for ( Dependency dependency : previousDependencies ) 359 | { 360 | callback.removedDependency( dependency ); 361 | } 362 | } 363 | 364 | /** 365 | * Registers the target file name for the specified artifact. 366 | * 367 | * @param artifact the artifact 368 | * @param targetFileName the target file name 369 | */ 370 | public void registerTargetFileName( Artifact artifact, String targetFileName ) 371 | { 372 | if ( dependenciesInfo != null ) 373 | { 374 | for ( DependencyInfo dependencyInfo : dependenciesInfo ) 375 | { 376 | if ( WarUtils.isRelated( artifact, dependencyInfo.getDependency() ) ) 377 | { 378 | dependencyInfo.setTargetFileName( targetFileName ); 379 | } 380 | } 381 | } 382 | } 383 | 384 | /** 385 | * Returns the cached target file name that matches the specified dependency, that is the target file name of the 386 | * previous run. 387 | *

388 | * The dependency object may have changed so the comparison is based on basic attributes of the dependency. 389 | * 390 | * @param dependency a dependency 391 | * @return the target file name of the last run for this dependency 392 | */ 393 | public String getCachedTargetFileName( Dependency dependency ) 394 | { 395 | if ( cache == null ) 396 | { 397 | return null; 398 | } 399 | for ( DependencyInfo dependencyInfo : cache.getDependenciesInfo() ) 400 | { 401 | final Dependency dependency2 = dependencyInfo.getDependency(); 402 | if ( StringUtils.equals( dependency.getGroupId(), dependency2.getGroupId() ) 403 | && StringUtils.equals( dependency.getArtifactId(), dependency2.getArtifactId() ) 404 | && StringUtils.equals( dependency.getType(), dependency2.getType() ) 405 | && StringUtils.equals( dependency.getClassifier(), dependency2.getClassifier() ) ) 406 | { 407 | 408 | return dependencyInfo.getTargetFileName(); 409 | 410 | } 411 | } 412 | return null; 413 | } 414 | 415 | // Private helpers 416 | 417 | private void doRegister( String id, String path ) 418 | { 419 | getFullStructure().add( path ); 420 | getStructure( id ).add( path ); 421 | } 422 | 423 | /** 424 | * Find a dependency that is similar from the specified dependency. 425 | * 426 | * @param dependency the dependency to find 427 | * @param dependencies a list of dependencies 428 | * @return a similar dependency or null if no similar dependency is found 429 | */ 430 | private Dependency findDependency( Dependency dependency, List dependencies ) 431 | { 432 | // CHECKSTYLE_OFF: LineLength 433 | for ( Dependency dep : dependencies ) 434 | { 435 | if ( dependency.getGroupId().equals( dep.getGroupId() ) 436 | && dependency.getArtifactId().equals( dep.getArtifactId() ) 437 | && dependency.getType().equals( dep.getType() ) 438 | && ( 439 | ( dependency.getClassifier() == null && dep.getClassifier() == null ) 440 | || ( dependency.getClassifier() != null && dependency.getClassifier().equals( dep.getClassifier() ) ) ) ) 441 | { 442 | return dep; 443 | } 444 | } 445 | return null; 446 | // CHECKSTYLE_ON: LineLength 447 | } 448 | 449 | private Dependency matchDependency( List dependencies, Dependency dependency ) 450 | { 451 | for ( Dependency dep : dependencies ) 452 | { 453 | if ( WarUtils.dependencyEquals( dep, dependency ) ) 454 | { 455 | return dep; 456 | } 457 | 458 | } 459 | return null; 460 | } 461 | 462 | private List createDependenciesInfoList( List dependencies ) 463 | { 464 | if ( dependencies == null ) 465 | { 466 | return Collections.emptyList(); 467 | } 468 | final List result = new ArrayList(); 469 | for ( Dependency dependency : dependencies ) 470 | { 471 | result.add( new DependencyInfo( dependency ) ); 472 | } 473 | return result; 474 | } 475 | 476 | private Object readResolve() 477 | { 478 | // the full structure should be resolved so let's rebuild it 479 | this.allFiles = new PathSet(); 480 | for ( PathSet pathSet : registeredFiles.values() ) 481 | { 482 | this.allFiles.addAll( pathSet ); 483 | } 484 | return this; 485 | } 486 | 487 | /** 488 | * Callback interface to handle events related to filepath registration in the webapp. 489 | */ 490 | public interface RegistrationCallback 491 | { 492 | 493 | /** 494 | * Called if the targetFilename for the specified ownerId has been registered successfully. 495 | *

496 | * This means that the targetFilename was unknown and has been registered successfully. 497 | * 498 | * @param ownerId the ownerId 499 | * @param targetFilename the relative path according to the root of the webapp 500 | * @throws IOException if an error occurred while handling this event 501 | */ 502 | void registered( String ownerId, String targetFilename ) 503 | throws IOException; 504 | 505 | /** 506 | * Called if the targetFilename for the specified ownerId has already been registered. 507 | *

508 | * This means that the targetFilename was known and belongs to the specified owner. 509 | * 510 | * @param ownerId the ownerId 511 | * @param targetFilename the relative path according to the root of the webapp 512 | * @throws IOException if an error occurred while handling this event 513 | */ 514 | void alreadyRegistered( String ownerId, String targetFilename ) 515 | throws IOException; 516 | 517 | /** 518 | * Called if the registration of the targetFilename for the specified ownerId has been refused 519 | * since the path already belongs to the actualOwnerId. 520 | *

521 | * This means that the targetFilename was known and does not belong to the specified owner. 522 | * 523 | * @param ownerId the ownerId 524 | * @param targetFilename the relative path according to the root of the webapp 525 | * @param actualOwnerId the actual owner 526 | * @throws IOException if an error occurred while handling this event 527 | */ 528 | void refused( String ownerId, String targetFilename, String actualOwnerId ) 529 | throws IOException; 530 | 531 | /** 532 | * Called if the targetFilename for the specified ownerId has been registered successfully by 533 | * superseding a deprecatedOwnerId, that is the previous owner of the file. 534 | *

535 | * This means that the targetFilename was known but for another owner. This usually happens after a 536 | * project's configuration change. As a result, the file has been registered successfully to the new owner. 537 | * 538 | * @param ownerId the ownerId 539 | * @param targetFilename the relative path according to the root of the webapp 540 | * @param deprecatedOwnerId the previous owner that does not exist anymore 541 | * @throws IOException if an error occurred while handling this event 542 | */ 543 | void superseded( String ownerId, String targetFilename, String deprecatedOwnerId ) 544 | throws IOException; 545 | 546 | /** 547 | * Called if the targetFilename for the specified ownerId has been registered successfully by 548 | * superseding a unknownOwnerId, that is an owner that does not exist anymore in the current project. 549 | *

550 | * This means that the targetFilename was known but for an owner that does not exist anymore. Hence the 551 | * file has been registered successfully to the new owner. 552 | * 553 | * @param ownerId the ownerId 554 | * @param targetFilename the relative path according to the root of the webapp 555 | * @param unknownOwnerId the previous owner that does not exist anymore 556 | * @throws IOException if an error occurred while handling this event 557 | */ 558 | void supersededUnknownOwner( String ownerId, String targetFilename, String unknownOwnerId ) 559 | throws IOException; 560 | } 561 | 562 | /** 563 | * Callback interface to handle events related to dependencies analysis. 564 | */ 565 | public interface DependenciesAnalysisCallback 566 | { 567 | 568 | /** 569 | * Called if the dependency has not changed since the last build. 570 | * 571 | * @param dependency the dependency that hasn't changed 572 | */ 573 | void unchangedDependency( Dependency dependency ); 574 | 575 | /** 576 | * Called if a new dependency has been added since the last build. 577 | * 578 | * @param dependency the new dependency 579 | */ 580 | void newDependency( Dependency dependency ); 581 | 582 | /** 583 | * Called if the dependency has been removed since the last build. 584 | * 585 | * @param dependency the dependency that has been removed 586 | */ 587 | void removedDependency( Dependency dependency ); 588 | 589 | /** 590 | * Called if the version of the dependency has changed since the last build. 591 | * 592 | * @param dependency the dependency 593 | * @param previousVersion the previous version of the dependency 594 | */ 595 | void updatedVersion( Dependency dependency, String previousVersion ); 596 | 597 | /** 598 | * Called if the scope of the dependency has changed since the last build. 599 | * 600 | * @param dependency the dependency 601 | * @param previousScope the previous scope 602 | */ 603 | void updatedScope( Dependency dependency, String previousScope ); 604 | 605 | /** 606 | * Called if the optional flag of the dependency has changed since the last build. 607 | * 608 | * @param dependency the dependency 609 | * @param previousOptional the previous optional flag 610 | */ 611 | void updatedOptionalFlag( Dependency dependency, boolean previousOptional ); 612 | 613 | /** 614 | * Called if the dependency has been updated for unknown reason. 615 | * 616 | * @param dependency the dependency 617 | * @param previousDep the previous dependency 618 | */ 619 | void updatedUnknown( Dependency dependency, Dependency previousDep ); 620 | 621 | } 622 | } 623 | --------------------------------------------------------------------------------