2009-03-05 10 views
45

Tôi có một ứng dụng web có chứa tệp kê khai, trong đó tôi viết phiên bản hiện tại của ứng dụng của tôi trong tác vụ tạo kiến. Tệp kê khai được tạo chính xác, nhưng khi tôi cố gắng đọc nó trong thời gian chạy, tôi nhận được một số tác dụng phụ lạ. Mã của tôi để đọc trong biểu hiện là một cái gì đó như thế này:Làm cách nào để đọc tệp kê khai cho webapp đang chạy trong apache tomcat?

InputStream manifestStream = Thread.currentThread() 
           .getContextClassLoader() 
           .getResourceAsStream("META-INFFFF/MANIFEST.MF"); 
    try { 
     Manifest manifest = new Manifest(manifestStream); 
     Attributes attributes = manifest.getMainAttributes(); 
     String impVersion = attributes.getValue("Implementation-Version"); 
     mVersionString = impVersion; 
    } 
    catch(IOException ex) { 
     logger.warn("Error while reading version: " + ex.getMessage()); 
    } 

Khi tôi đính kèm eclipse để tomcat, tôi thấy rằng mã trên hoạt động, nhưng có vẻ như để có được một file manifest khác nhau so với cái tôi mong đợi, mà Tôi có thể nói vì phiên bản kiến ​​và dấu thời gian xây dựng đều khác nhau. Sau đó, tôi đặt "META-INFFFF" vào đó, và đoạn mã trên vẫn hoạt động! Điều này có nghĩa là tôi đang đọc một số biểu hiện khác, không phải của tôi. Tôi cũng đã thử

this.getClass().getClassLoader().getResourceAsStream(...) 

Nhưng kết quả là như nhau. Cách thích hợp để đọc tệp kê khai từ bên trong của một ứng dụng web chạy trong tomcat là gì?

Chỉnh sửa: Cảm ơn bạn đã đề xuất cho đến thời điểm này. Ngoài ra, tôi nên lưu ý rằng tôi am chạy tomcat độc lập; Tôi khởi động nó từ dòng lệnh, và sau đó đính kèm vào cá thể đang chạy trong trình gỡ rối của Eclipse. Điều đó không nên tạo nên sự khác biệt, phải không?

+0

@ PascalĐó là câu trả lời đúng đắn. Thêm một số xử lý ngoại lệ trong trường hợp MANIFEST của bạn không tồn tại (tức là:) và nó phải là A1. – jmelanson

+0

Phương pháp phổ quát này đã giúp tôi: [http://stackoverflow.com/a/29103019/3158918] – user3158918

Trả lời

1

Không biết về cách "chính thức" để đọc nó, nhưng nếu MANIFEST.MF không thể được tải đúng như một tài nguyên, cách cố gắng lấy được đường dẫn của nó từ một "ServletContext.getRealPath()" trên một số đường dẫn web được xác định trong ứng dụng của bạn?

Viết phiên bản ứng dụng cũng cho một số địa điểm khác (tệp thuộc tính trong WEB-INF/lớp) do kiến ​​trong khi xây dựng là một giải pháp khác xuất hiện trong tâm trí của tôi.

86

Có thể tác dụng phụ của bạn đến từ thực tế là hầu như tất cả các lọ bao gồm một MANIFEST.MF và bạn không nhận được đúng. Để đọc MANIFEST.MF từ webapp, tôi sẽ nói:

ServletContext application = getServletConfig().getServletContext(); 
InputStream inputStream = application.getResourceAsStream("/META-INF/MANIFEST.MF"); 
Manifest manifest = new Manifest(inputStream); 

Xin lưu ý rằng chạy Tomcat từ Eclipse không giống như chạy Tomcat đơn thuần như Eclipse chơi với trình nạp lớp.

+1

Thật vậy, tệp kê khai chiến tranh sẽ không nằm trên đường dẫn lớp. –

+2

+1 để cung cấp mã thực sự thực sự hoạt động. –

+4

Điều này rõ ràng là câu trả lời đúng +1 –

2

Trình tải lớp mặc định hoạt động là trì hoãn phụ huynh trước khi tìm kiếm tài nguyên của riêng họ. Vì vậy, nếu trình tải lớp cấp độ gốc có bất kỳ tệp kê khai nào, đó là những gì bạn sẽ nhận được. Thực tế, các máy chủ ứng dụng không nhất thiết phải làm điều này, để cho phép các ứng dụng ghi đè lên các phiên bản của các thư viện. Hơn nữa, trình nạp lớp có thể có nhiều lọ và do đó có nhiều tệp kê khai.

Nó có thể nhận URL tài nguyên của một trong những tài nguyên được đặt tên duy nhất của bạn. Mở một kết nối. Truyền tới JarURLConnection. Nhận số JarFile. Tải tệp kê khai từ đó. Điều đó có thể không hoạt động, đặc biệt nếu Tomcat phát nổ chiến tranh.

[Cập nhật] Tất nhiên, bản thân tệp chiến tranh không có trên đường dẫn lớp. Đường dẫn lớp sẽ có thứ gì đó như WEB-INF/lib/(.jar | .zip) và WEB-INF/classes /. Bắt nguồn từ ServletContext sẽ hoạt động.

Giải pháp tốt nhất: Làm điều gì đó khác biệt.:)

10

hơi muộn, nhưng hoạt động này đối với tôi (web Appl trong Glassfish)

Properties prop = new Properties(); 
prop.load(getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF")); 
System.out.println("All attributes:" + prop.stringPropertyNames()); 
System.out.println(prop.getProperty("{whatever attribute you want}")); 
+9

chú ý: theo dõi [RFC-822] (http://www.ietf.org/rfc/rfc0822.txt), bạn sẽ tìm thấy các vấn đề bằng cách sử dụng 'Thuộc tính' vì các giá trị dài được chia thành nhiều dòng hơn. Thay vào đó, hãy sử dụng lớp 'Manifest' của người dùng. –

3

Cố gắng sử dụng jcabi-manifests, mà làm tất cả công việc tải này cho bạn. Ví dụ:

String version = Manifests.read("My-Version"); 

tải My-Version thuộc tính từ một trong các tệp MANIFEST.MF hiện có.

Quan trọng cần đề cập (chi tiết hơn là here) trong hầu hết các bộ chứa lớp hiện tại của trình chứa web không giống với trình nạp lớp ngữ cảnh servlet. Đó là lý do tại sao bạn nên thêm bối cảnh servlet của bạn để đăng ký trong thời gian chạy (more info):

Manifests.append(servletContext); 

Ngoài ra, kiểm tra này: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

2

Các biểu hiện đúng tồn tại trong thư mục gốc ứng dụng tại máy chủ. Tìm hiểu gốc rễ appication, ví dụ bằng cách tìm hiểu classpath của lớp học của bạn:

String rootPath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath() 

Sau đó thay thế các đường dẫn ở trên với đường dẫn thành lập: ví dụ Glassfish:

/applications/<webProject>/META-INF/MANIFEST.MF 

Nó làm việc cho tôi.

0

Đây là những gì tôi làm để in các phiên bản khác nhau thành tệp nhật ký. Tôi đã mã hóa đường dẫn mở rộng nhưng các ứng dụng có thể sử dụng servletContext.getRealPath("/") để đọc đường dẫn đầy đủ đến thư mục webapp. Có thể in chỉ các thư viện hoặc tất cả mọi thứ từ thư mục lib.

// print library versions (jersey-common.jar, jackson-core-2.6.1.jar) 
try { 
    List<String> jars = Arrays.asList("jersey-common", "jackson-core", "openjpa", "mylib"); 
    StringBuilder verbuf = new StringBuilder(); 
    for(File file : new File("/opt/tomcat/webapps/myapp/WEB-INF/lib/").listFiles()) { 
     String name = file.getName(); 
     if (file.isDirectory() || !file.isFile() || !name.endsWith(".jar")) continue; 
     name = name.substring(0, name.length()-4); 
     boolean found = jars.contains(name); 
     if (!found) { 
      int idx = name.lastIndexOf('-'); 
      if (idx>0) 
       found = jars.contains(name.substring(0, idx)); 
     } 
     if (!found) continue; 

     JarFile jarFile = new JarFile(file, false); 
     try { 
      String ver; 
      Manifest mf = jarFile.getManifest(); 
      if (mf!=null) { 
       ver = mf.getMainAttributes().getValue("Bundle-Version"); 
       if (ver==null || ver.isEmpty()) 
        ver = mf.getMainAttributes().getValue("Implementation-Version"); 
      } else ver=null; 
      if (verbuf.length()>0) verbuf.append(", "); 
      verbuf.append(name + "=" + (ver!=null?ver:""));       
     } finally { 
      jarFile.close(); 
     } 
    } 
    System.out.println(verbuf.toString()); 
} catch(Exception ex) { 
    ex.printStackTrace(); 
}