トップ 一覧 ping 検索 ヘルプ RSS ログイン

Java Windowsファイル共有サービス(CIFS)経由でファイルを書き込むの変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!!!Java Windowsファイル共有サービス(CIFS)経由でファイルを書き込む
[Java]
[Java][JAX-RS]

*アプリケーションサーバー等、サービスで動くアプリケーションは、ログインユーザーとは別権限で動作しており、ファイル共有されたドライブのファイル参照、書き出しが出来ない。
*JCIFSライブラリを利用して対応する
**http://jcifs.samba.org/

!!書き込みユーティリティ例
 package info.typea.util;
 
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 
 import jcifs.smb.SmbException;
 import jcifs.smb.SmbFile;
 import jcifs.smb.SmbFileOutputStream;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * ファイルシステムユーティリティ
  *
  */
 public class FileSystemUtils {
     protected static Logger logger = LoggerFactory.getLogger(FileSystemUtils.class);
     private static final int BUF_SIZE = 4096;
     
     private FileSystemUtils(){}
     
     /**
      * 通常のファイルシステムもしくは CIFS(Windowsファイル共有サービス) にファイルを書き込む
      * 
      * @param is 書き込み内容
      * @param file 書き込み対象ファイル
      * @param isCifs CIFS か否か
      * @return
      */
     public static FileSystemUtilInfo writeToFile(
             InputStream is, 
             File file,
             boolean isCifs,            
             String user, 
             String password) {
         
         if (isCifs) {
             return writeToCifsFile(is, file, user, password);
         } else {
             return writeToLocalFile(is, file);
         }
     }
          
     /**
      * java.io.File から、SmbFile オブジェクトを生成する
      * 
      * @param targetFile
      * @param user
      * @param password
      * @return
      */
     public static SmbFile createSmbFileFromFile(
             File targetFile,            
             String user, 
             String password) {
         
         SmbFile file = null;
         try {
             file = new SmbFile(
                 cifsUrl( 
                     user,
                     cisfPassword(password),
                     cisfPath(targetFile.getAbsolutePath())));
             
         } catch (MalformedURLException e) {
             // TODO
         }
         
         return file;
     }
      
     /**
      * 通常のファイルシステムにファイルを作成
      * 
      * @param is
      * @param targetFile
      * @return
      */
     private static FileSystemUtilInfo writeToLocalFile(InputStream is, File targetFile) {
         
         FileSystemUtilInfo info = new FileSystemUtilInfo();
         
         FileOutputStream fos = null;
         try {
             fos = new FileOutputStream(targetFile);
             BufferedInputStream bis = new BufferedInputStream(is);
             
             int len = 0;
             long fileSize = 0;
             byte[] buffer = new byte[BUF_SIZE];
             while ((len = bis.read(buffer)) >= 0) { 
                 fos.write(buffer,0, len);
                 fileSize += len;
             }
             info.setFileSize(fileSize);
             
             bis.close();
         } catch(Exception e) {
             throw new IllegalStateException(e);
         } finally {
             try {
                 fos.close();
             } catch (Exception e2) {}
         }
         return info;
     }
     
     /**
      * CIFS ファイルシステムにファイルを作成
      * 
      * @param is
      * @param targetFile
      * @return
      * @see http://jcifs.samba.org/src/docs/api/jcifs/smb/SmbFile.html
      */
     private static FileSystemUtilInfo writeToCifsFile(
             InputStream is, 
             File targetFile, 
             String user, 
             String password) {
                 
         FileSystemUtilInfo info = new FileSystemUtilInfo();
         try {
             makeCifsDirectories(targetFile.getParentFile(), user, password);
             SmbFile file = new SmbFile(
                 cifsUrl( 
                     user,
                     cisfPassword(password),
                     cisfPath(targetFile.getAbsolutePath())));
 
             if (!file.exists()) {
                 file.createNewFile();
             }
             SmbFileOutputStream fos = new SmbFileOutputStream(file);
             BufferedInputStream bis = new BufferedInputStream(is);
             
             int len = 0;
             long fileSize = 0;
             byte[] buffer = new byte[BUF_SIZE];
             while ((len = bis.read(buffer)) >= 0) { 
                 fos.write(buffer,0, len);
                 fileSize += len;
             }
             info.setFileSize(fileSize);
             
             bis.close();
             
         } catch (Exception e) {
             // TODO
         }
         
         return info;
     }
     
     /**
      * CIFS ディレクトリが存在しない場合、作成する
      * 
      * @param dir
      * @param user
      * @param password
      * @throws MalformedURLException
      * @throws SmbException
      */
     private static void makeCifsDirectories(
             File dir, 
             String user, 
             String password) throws MalformedURLException, SmbException {
         
         SmbFile cifsDir = new SmbFile(
             cifsUrl( 
                 user,
                 cisfPassword(password),
                 cisfPath(dir.getAbsolutePath())));
         
         if (!cifsDir.exists()) {
             cifsDir.mkdirs();
         }
     }
     
     /**
      * CIFS アクセス URL
      * @param user
      * @param password
      * @param path
      * @return
      */
     private static String cifsUrl(String user, String password, String path) {
         return String.format("smb://%s:%s@%s",user,password,path);
     }
     /**
      * '@' is URL encoded with the '%40' hexcode escape
      * 
      * @param password
      * @return
      */
     private static String cisfPassword(String password) {
         return password.replaceAll("@", "%40");
     }
     
     /**
      * "\\" で始まる、UNCパス を "server/share/path/to/file.txt" のような書式に変換
      * 
      * @param path
      * @return
      */
     private static String cisfPath(String path) {
         // \\ を取り除く
         if (path.substring(0,2).equals("\\\\")) {
             path = path.substring(2);
         }
         return path.replaceAll("\\\\", "\\/");
     }
 
     
     /**
      *  結果情報
      *
      */
     public static class FileSystemUtilInfo {
         private long fileSize;
 
         public long getFileSize() {
             return fileSize;
         }
 
         public void setFileSize(long fileSize) {
             this.fileSize = fileSize;
         }
     }
 }
!!JAX-RS のプロバイダ例
*SmbFile を JAX-RS のレスポンスとして返すためのプロバイダ
 package info.typea.provider;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 
 import jcifs.smb.SmbException;
 import jcifs.smb.SmbFile;
 import jcifs.smb.SmbFileInputStream;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * Windows ファイル共有 サービス(CIFS) ファイル 用 JAX-RS プロバイダー
  * 
  * @see org.apache.wink.common.internal.providers.entity.FileProvider
  */
 @Provider
 @Produces({ "*/*" })
 @Consumes({ "*/*" })
 public class SmbFileProvider implements MessageBodyWriter<SmbFile> {
     private static final Logger logger = LoggerFactory.getLogger(SmbFileProvider.class);
 
     @Override
     public long getSize(SmbFile t, Class<?> type, Type genericType, Annotation[] annotations,
             MediaType mediaType) {
         try {
             return t.length();
         } catch (SmbException e) {
             return 0;
         }
     }
 
     @Override
     public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations,
             MediaType mediaType) {
         return SmbFile.class.isAssignableFrom(type);
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     @Override
     public void writeTo(
             SmbFile t, 
             Class<?> type, 
             Type genericType, 
             Annotation[] annotations,
             MediaType mediaType, 
             MultivaluedMap<String, Object> httpHeaders,
             OutputStream entityStream) throws IOException, WebApplicationException {
 
         try {
             final SmbFile smbFile = t;
             final OutputStream os = entityStream;
             
             AccessController.doPrivileged(new PrivilegedExceptionAction() {
                 public Object run() throws IOException {
                     if ((!(smbFile.canRead())) || (smbFile.isDirectory())) {
                         if (SmbFileProvider.logger.isWarnEnabled()) {
                             SmbFileProvider.logger.error(String
                                 .format("cannotUseFileAsResponse %s", smbFile.getPath()));
                         }
 
                         throw new WebApplicationException();
                     }
                     SmbFileInputStream fis = new SmbFileInputStream(smbFile);
                     try {
                         SmbFileProvider.this.pipe(fis, os);
                     } finally {
                         fis.close();
                     }
 
                     return null;
                 }
             });
         } catch (PrivilegedActionException e) {
             if (e.getException() instanceof IOException)
                 throw ((IOException) e.getException());
             if (e.getException() instanceof WebApplicationException)
                 throw ((WebApplicationException) e.getException());
             throw new WebApplicationException(e.getException());
         }
     }
 
     private void pipe(InputStream is, OutputStream os) throws IOException {
         byte[] ba = new byte[1024];
         int i = is.read(ba);
         while (i != -1) {
             os.write(ba, 0, i);
             i = is.read(ba);
         }
     }
 }