[Maven] properties내용을 command창에서 바로 입력하기

Published on: 2013. 11. 14. 14:14 by louis.dev
Maven에서는 .properties파일 또는 pom.xml에 직접 <properties>를 통하여 DB의 접속정보라던지, 특정 dependency의 버전이라던지 하는 설정정보를 저장하여 관리할수 있다.(properties에 관한 자세한 내용은 여기에서) 이렇게 저장된 데이터들 중 pom.xml이나 properties파일에 직접 저장하기 껄끄러운데이터들이 있을 수 있다. 예를 들어 telnet이나 ftp에 로그인하기 위한 아이디와 패스워드 정보들은 pom.xml이나 .properties에 텍스트형태로 저장하게 되면 다른사람에게 그대로 노출이되어 보안에 취약하게 된다. 이런 껄끄러운 데이터들은 파일에 직접 저장하는 것이 아니라 Maven의 goal을 실행할때 파라미터로 전달하는 방법을 사용하면 된다. 아래의 설정은 Maven의 ant plugin으로 FTP를 사용하여 파일을 업로드하는 설정이다. 구체적으로 설명하지 않았지만 중요하게 봐야할 점은 FTP업로드시 userid와 password를 properties를 사용하게끔 설정했다는 것이다.
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>ftp</id>
      <phase>install</phase>
      <configuration>
        <tasks>
          <echo>SendFTP</echo>
          <ftp action="send" server="SERVERIP"
              remotedir="/a/b" userid="${ftp.userid}"
              password="${ftp.password}" depends="no"
              verbose="yes" binary="yes">
              <fileset dir="modules/my-module/target">
                <include name="my-static-file.zip" />
              </fileset>
            </ftp>
        </tasks>
      </configuration>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
  <dependencies>
    <dependency>
      <groupId>ant</groupId>
      <artifactId>ant-commons-net</artifactId>
      <version>1.6.5</version>
    </dependency>
    <dependency>
      <groupId>commons-net</groupId>
      <artifactId>commons-net</artifactId>
      <version>1.4.1</version>
    </dependency>
  </dependencies>
</plugin>
그리고 package goal을 실행할때 다음과 같이 입력한다.
$mvn package -Dftp.userid=krespo -Dftp.password=myftppassword
위에서 보듯이 ${ftp.userid}에는 krespo가 ${ftp.password}에는 myftppassword가 들어가는것을 확인해 보지 않고도 알수가 있다. 이렇듯 파라미터로 정보를 넘기려면
-D{key}={value}
형태로만 넣으면 어떠한 값이라도 동적으로 전달할 수 있게 된다.

[Maven] Dependency Scope의 종류

Published on: 2013. 11. 14. 14:10 by louis.dev
maven은 dependency 엘리먼트 하위의 scope 엘리먼트를 통해 포함하려는 라이브러리의 범위를 지정할 수 있다. Maven 3에서는 다음의 여섯가지 옵션을 지원하고 있다.
  • compile : 기본 scope이다. 만약 dependency에 아무것도 입력하지 않았다면 기본적으로 입력되는 scope이다. 이 옵션은 프로젝트의 모든 classpath에 추가된다(테스트 중이건 런타임 중이건 상관없이).
  • provided : 이 옵션은 compile과 매우 비슷하지만, 실행시 의존관계를 제공하는 JDK나 Web Container(tomcat 같은)에 대해서 적용된다.  예를 들어 Java Enterprise Edition Web application을 개발할때 Servlet API나 Java EE API들은 "provided" scope로 지정해야한다. 왜냐하면 Servlet API같은 경우는 Servlet Container 자체에서 지원해 주기 때문에(Tomcat 같은 경우는 ${tomcat home directory}/lib 디렉토리에 있는 Servlet 라이브러리를 사용) 컴파일시 또는 테스트시에는 필요하지만 실행시에는 필요하지 않기 때문이다.
  • runtime : 컴파일 시에는 필요하지 않지만 실행시에 사용되는 경우 사용한다. 이 옵션은 런타임, 테스트 시 classpath에 추가 되지만, 컴파일시에는 추가 되지 않는다.
  • test : 일반적인 경우에는 필요하지 않고 테스트시에만 필요한 경우 사용한다.
  • system : 해당 jar를 포함해야 한다고 명시적으로 입력 하는 것을 제외하고는 provided와 유사하다. 선언된 artifact들은 항상 사용가능하지만 Maven의 central repository에서 찾아서 가져오는 것은 아니다.
  • import : Maven 2.0.9 이상의 버전에서 지원하는 scope로서, 이 scope는 <dependencyManagement> 섹션에서 pom의 의존관계에 대해 사용된다. 지정된 pom이 해당 pom의 <dependencyManagement> 영역에 있는 의존관계로 대체됨을 뜻한다.
자세한 예제는 메이븐 공식 홈페이지 에서 확인할 수 있다.

[Maven] package org.junit does not exists 에러 발생시

Published on: 2013. 11. 14. 14:09 by louis.dev
오늘 우연히 Maven을 통해 packaging을 진행을 하다가 이런 에러를 발생시키면서 packaging이 진행되지 않았다.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.1:compile (default-compile) on project ${프로젝트명}: Compilation failure: Compilation failure:
[ERROR] ${에러 소스파일 경로}\${파일명}.java:[10,38] package org.junit.runners.Parameterized does not exist
[ERROR] ${에러 소스파일 경로}\${파일명}.java:[10,38] package org.junit.runners.Parameterized does not exist
[ERROR]
[ERROR] ${에러 소스파일 경로}\${파일명}.java:[10,38] package org.junit.runners.Parameterized does not exist
[ERROR]
[ERROR] ${에러 소스파일 경로}\${파일명}.java:[10,38] package org.junit.runners.Parameterized does not exist
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <goals> -rf :Infinite
에러내용을 읽어보니 org.junit.runers.Parameterized라는 패키지가 존재하지 않는다는 문제였다. 아마  검색을 통하여 이 포스트를 찾았다면 에러가 발생된 패키지 명은 달라도 모두 junit에서 발생한 문제일 것이다. 이문제는 컴파일 단계에서 junit 라이브러리가 포함이 되지 않아 발생하는 문제로 Maven의 버그가 아니라 pom파일의 dependency 설정때문에 발생한다.
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.8.1</version>
	<scope>test</scope>
</dependency>
위와같이 pom파일의 dependency 설정을통해 junit 라이브러리를 추가하게 되는데 이때 해당라이브러리의 사용범위를 지정할수있도록 Maven은 scope라는 엘리먼트를 지원해 주고 있다. 이때 scope를 test로 선언하게 되면 해당라이브러리는 테스트 중에만 사용을 하고 실제 packaging 중에는 포함이 되지 않는다. 이렇게 사용범위를 지정함으로서 불필요한 라이브러리 포함을 줄여 어플리케이션의 사이즈를 줄일수 있도록 만들게 되었다. 따라서 위와 같은 빌드 실패는 어플리케이션이 빌드되고 배포 되어질때 junit 라이브러리는 scope 설정때문에 패키징에서 제외되었음으로 org.junit.runers.Parameterized 패키지가 존재하지 않아 발생되는 문제이다. 필자의 경우에는 실제 org.junit.runers.Parameterized 패키지를 사용한 것이 아니라 mybatis의 @Param 어노테이션을 사용하려고 이클립스에서 지원하는 code assist 기능을 사용하여 입력하였고 그때 잘못 입력하여 java파일 상단에 import org.junit.runners.Parameterized.Parameters; 가 포함되었기 때문에 위와 같은 문제가 발생했다. 만약 각자의 코트에서 junit class를 런타임시에도 필요하다면(그럴일은 거의 없겠지만) scope 엘리먼트를 제거하면 되고, 그렇지 않으면 불필요한 import 문을 제거해 주면 깔끔하게 해결된다. 다른 dependency scope를 확인하고 싶다면 여기를 통해 확인하자.

[Maven] Maven 빌드가 느리게 되는 경우 처리방법

Published on: 2013. 11. 14. 13:21 by louis.dev
maven 빌드가 느려지는 경우는 다양한 경우가 있었지만, 내 경우의 경험을 써보고자 한다. 

 이전에 Maven을 통해 war 파일로 패키징을 진행할때 시간이 15분 이상 넘게 걸리는 경우가 있었다. 이때 webistrano를 이용해 빌드하고 배포를 진행했기 때문에 webistrano문제이겠거니 하고 대수롭지 않게 넘겼다. 
그런데 프로젝트 후반으로 갈수록 배포할 일이 많아졌고 그때마다 15분이나 되는 시간을 기다려야했기 때문에 결국 빌드가 느리게 되는 현상을 찾아보기로 하였다. 

이것저것 로그를 보다가 콘솔에서 직접 Maven 빌드를 진행해 보았는데 Maven 빌드 자체가 느리게 되는 문제를 확인하였다. 여기서 문제는 maven-metadata.xml과 같은 version 정보를 담고있는 xml파일을 다운로드 하는데 너무 오랜 시간이 걸리기 때문이라는 결론을 얻게 되었다. 

 회사에서는 사내에서 사용할 Nexus서버를 구축하였고, 프로젝트의 pom.xml파일에 사내 Nexus를 repository로 추가한 상태였다. 그렇기 때문에 maven-metadata.xml을 사내 repository에서 다운로드 받고 있었다.(빌드시 로그도 사내 repository에서 다운받고 있었다) 결국 문제는 네트워크 구조상의 문제였다. 


배포하려는 서버는 외부에서 들어오는 요청은 막혀있는 상태(보안을 위해)의 서버였다. 그렇기 때문에 wget 명령으로 외부페이지의 데이터를 긁어 온다거나 하는 작업을 수행할 수가 없었다. 


뜬금없지만 Maven의 구조에 대해서 먼저 말해보겠다. Maven의 설정파일인 pom.xml파일은 상속구조로 되어있다. Maven core안에 pom.xml이 기본적인 설정사항을 가지고 있고, 각 프로젝트마다 저장한 pom.xml파일이 상위의(Core의) pom.xml 파일을 상속받아(눈에보이지 않지만) 구현하고 있는 구조로 되어있다. 

이때 상위 pom.xml파일을 확인해 보면 해당 파일에 repository설정으로 Maven 중앙저장소가 세팅이 되어있고, 그렇기 때문에 우리는 각 프로젝트의 pom.xml에 repository 설정을 하지 않아도 library, maven-metadata.xml파일과 같은 파일을 자동으로 다운로드 받을수 있었던 것이다. Maven이 위와같은 구조로 되어있기 때문에 배포하려는 프로젝트는 2개의 repository(Maven에서 지원하는 중앙저장소, 사내에서 사용하는 Nexus)를 가지고 있게 되었다. 

따라서 library등을 다운로드할때 먼저 Maven 중앙저장소에서 라이브러리를 로컬에 다운로드 받고 만약 중앙저장소에 없는 라이브러리일 경우 사내 저장소에서 찾는 구조가 되었다. 이때 Maven 중앙저장소로 라이브러리와 버전정보 xml파일을 다운로드 받으려면 외부 네트워크로 트래픽이 나가야 하는데 네트워크 구조상 외부로 트래픽이 나갈수가 없어 계속 중앙저장소의 library, xml파일을 timeout 이 날때까지 계속 요청하다가 결국 받지 못하게 되고, 그 이후에 사내 저장소로 요청을하여 전체적으로 빌드 타임이 길어지는 문제가 있었다. 위와같은 문제는 maven의 global setting파일인 settings.xml파일에

중앙저장소 말고 특정한 저장소를 사용하겠다
라고 하는 세팅을 해주면 된다.  리눅스는 ${home}/.m2 디렉토리이고 윈도우는 C:사용자${사용자명}.m2 디렉토리안에 settings.xml파일을 생성해 주면 된다. 그리고 그 파일 안에 다음과 같이 설정하면 중앙저장소가 아닌 사내 저장소에서만 라이브러리를 다운로드 받을수 있게 된다.
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <mirrors>
    <mirror>
      <id>${아이디지정}</id>
      <mirrorOf>*</mirrorOf>
      <url>${사용하고자하는 maven repository 설정}</url>
    </mirror>
  </mirrors>

  <profiles>
    <profile>
      <id>public</id>
      <repositories>
        <repository>
          <id>central</id>
          <url>http://central</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>true</enabled></snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
      <pluginRepository>
        <id>central</id>
        <url>http://central</url>
        <releases><enabled>true</enabled></releases>
        <snapshots><enabled>true</enabled></snapshots>
      </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>

  <activeProfiles>
    <activeProfile>public</activeProfile>
  </activeProfiles>
</settings>
위와같이 설정하면 maven의 중앙저장소를 원하는 위치로 변경할 수 있다.



Maven - 외부 플러그인을 사용하기 위한 플러그인 Repository사용하기.

Published on: 2011. 12. 7. 14:10 by louis.dev
기본 플러그인과 모조 프로젝트에서 제공하는 플러그인은 메이븐의 중앙 저장소에서 제공해주는 플러그인이기 때문에 따로 plugin repository를 등록하지 않아도 되었다. 그러나 가끔 중앙저장소 말고 다른곳에서 제공해주는 플러그인을 사용해야 할때는 pom.xml에 외부 저장소의 위치를 지정해 줘야 한다.

	
		
			repository-id
			http://plugin.repository.com