001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.hayabusa.report2; 017 018import java.io.IOException; 019import java.net.InetSocketAddress; 020import java.net.Socket; 021 022import org.opengion.hayabusa.common.HybsSystemException; 023// import org.opengion.fukurou.system.ThrowUtil; // 6.4.2.0 (2016/01/29) // 8.5.4.2 (2024/01/12) 024 025/** 026 * OpenOfficeのプロセスを表すクラスです。 027 * 028 * このクラスでは、TCPによりプロセスに接続を行います。 029 * 基本的には、パイプ名による接続({@link SOfficeProcess})を利用すべきですが、 030 * x64環境で、64Bit版のJavaを起動した場合、パイプ接続では、UnsatisfiedLinkErrorが発生します。 031 * このような場合では、TCP接続を利用することで、上記エラーを回避することができます。 032 * 033 * @version 4.0 034 * @author Hiroki Nakamura 035 * @since JDK5.0, 036 */ 037public final class SOfficeProcessTcp extends SOfficeProcess { 038 039 private static final boolean[] PORTS = new boolean[512]; // 6.4.1.1 (2016/01/16) ports → PORTS refactoring 040 private static final Object LOCK = new Object(); // 6.4.1.1 (2016/01/16) lock → LOCK refactoring 041 042 private final int initPort; 043 private final int thisPort; 044 045 /** 046 * コンストラクタです。 047 * 048 * @param id プロセスID 049 * @param initPort 初期ポート 050 */ 051 protected SOfficeProcessTcp( final String id, final int initPort ) { 052 super( id ); 053 054 this.initPort = initPort; 055 this.thisPort = getThisPort(); 056 } 057 058 /** 059 * TCP接続ポート番号を取得します。 060 * 061 * @return TCP接続ポート番号 062 */ 063 private int getThisPort() { 064// try { 065// Thread.sleep( 100 ); // 切断後すぐにopenされると、ポートチェックで引っかかるため100msWAIT 066// } 067// catch( final InterruptedException ex ) { 068// // ここの Exception は、無視します。 069// } 070 try { Thread.sleep( 100 ); } catch( final InterruptedException ignored ) {} // 8.5.4.2 (2024/01/12) PMD 7.0.0 EmptyCatchBlock 071 072 int port = -1; 073 synchronized( LOCK ) { 074 for( int i=0; i<PORTS.length; i++ ) { 075 // 6.0.0.1 (2014/04/25) These nested if statements could be combined 076 if( !PORTS[i] && checkPort( initPort + i ) ) { 077 PORTS[i] = true; 078 port = initPort + i; 079 break; 080 } 081 } 082 } 083 if( port < 0 ) { 084 throw new HybsSystemException( "TCP接続ポートを取得することができません" ); 085 } 086 087 return port; 088 } 089 090 /** 091 * 引数のポートが使用中かどうかを調べます。 092 * 093 * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。 094 * 095 * @param port ポート番号 096 * 097 * @return 使用中かどうか 098 */ 099 private boolean checkPort( final int port ) { 100 boolean flg = false; 101 // 8.5.4.2 (2024/01/12) PMD 7.0.0 UseTryWithResources 対応 102// Socket sk = null; 103// try { 104// sk = new Socket(); 105 try ( Socket sk = new Socket() ) { 106 sk.connect( new InetSocketAddress( "localhost", port ) ); 107 } 108 catch( final IOException ex ) { 109 flg = true; 110 } 111// finally { 112// try { 113// if( sk != null ) { sk.close(); } // 5.5.2.6 (2012/05/25) findbugs対応 114// } 115// catch( final IOException ex ) { 116// System.err.println( ThrowUtil.ogStackTrace( ex ) ); // 6.4.2.0 (2016/01/29) 117// } 118// } 119 return flg; 120 } 121 122 /** 123 * Pipe名をキーにOpenOfficeのプロセスに接続するための文字列を生成します。 124 * ※TCP接続の場合、キーのPipe名は無視され、内部的に管理されるポート番号一覧より 125 * 接続ポートを取得します。 126 * 127 * @param key Pipe名(無視されます) 128 * 129 * @return 接続文字列 130 * @og.rtnNotNull 131 */ 132 @Override 133 protected String getConnParam( final String key ) { 134 System.out.println( "[INFO]OOo:TCP Connection Start,port=" + thisPort ); 135 return "uno:socket,host=localhost,tcpNoDelay=1,port=" + thisPort + ";urp;StarOffice.ComponentContext"; 136 } 137 138 /** 139 * Pipe名をキーにOpenOfficeのプロセスを生成するためのパラメーター文字列を生成します。 140 * ※TCP接続の場合、キーのPipe名は無視され、内部的に管理されるポート番号一覧より 141 * 接続ポートを取得します。 142 * 143 * @param key Pipe名(無視されます) 144 * 145 * @return プロセス生成パラメーター 146 * @og.rtnNotNull 147 */ 148 @Override 149 protected String getProcParam( final String key ) { 150 return "-accept=socket,host=localhost,port=" + thisPort + ";urp;"; 151 } 152 153 /** 154 * プロセスを終了します。 155 * また、同時に環境設定用のファイルも削除します。 156 * ここでは、プロセスを終了すると同時に、そのプロセスのポート番号を開放し、 157 * 次に起動されるプロセスで利用できるようにします。 158 */ 159 @Override 160 public void close() { 161 super.close(); 162 synchronized( LOCK ) { 163 PORTS[thisPort-initPort] = false; 164 } 165 System.out.println( "[INFO]OOo:TCP Connection End(Release),port=" + thisPort ); 166 } 167}