透過 Apache Common VFS 套件 取回遠端的資源

能使用的協定參考：
@see <a href="https://commons.apache.org/proper/commons-vfs/filesystems.html">commons-vfs filesystems</a>
548649
public String getFromRemote(String uri){

        // clear cache
        fileSystem.getFilesCache().close();

        String remoteContent ;
        String remoteEncoding = "utf-8";

        log.debug("getFromRemote: Loading remote URI=" + uri);
        FileContent fileContent ;

        try {

            FileSystemOptions fsOptions = new FileSystemOptions();
            // set userAgent
            HttpFileSystemConfigBuilder.getInstance().setUserAgent(fsOptions, userAgent);

            // set cookie if cookies set
            if (0 < this.cookies.size()) {
                HttpFileSystemConfigBuilder.getInstance().setCookies(fsOptions, getCookies(uri));
            }

            log.debug("getFromRemote: userAgent=" + userAgent);
            log.debug("getFromRemote: cookieSize=" + cookies.size());
            log.debug("getFromRemote: cookies=" + cookies.toString());

            fileContent = fileSystem.resolveFile(uri, fsOptions).getContent();

            // 2016-03-22 only pure http/https auto detect encoding
            if ("http".equalsIgnoreCase(uri.substring(0, 4))) {
                fileContent.getSize();  // pass a bug {@link https://issues.apache.org/jira/browse/VFS-427}
                remoteEncoding = fileContent.getContentInfo().getContentEncoding();
            }

            log.debug("getFromRemote: remoteEncoding=" + remoteEncoding + "(auto detect) ");

            // 2016-03-21 修正zip file getContentEncoding 為null
            if (null == remoteEncoding) remoteEncoding = "utf-8";

            if (!"utf".equalsIgnoreCase(remoteEncoding.substring(0, 3))) {
                log.debug("getFromRemote: remote content encoding=" + remoteEncoding);

                // force charset encoding if setRemoteEncoding set
                if (!"utf".equalsIgnoreCase(encoding.substring(0, 3))) {
                    remoteEncoding = encoding;
                } else {
                    // auto detecting encoding
                    remoteEncoding = detectCharset(IOUtils.toByteArray(fileContent.getInputStream()));
                    log.debug("getFromRemote: real encoding=" + remoteEncoding);
                }
            }

            // 透過  Apache VFS 取回指定的遠端資料
            // 2016-02-29 fixed
            remoteContent = IOUtils.toString(fileContent.getInputStream(), remoteEncoding);

        } catch(FileSystemException fse){
            log.warn("getFromRemote: FileSystemException=" + fse.getMessage());
            remoteContent =null;
        }catch(IOException ioe){
            // return empty
            log.warn("getFromRemote: IOException=" + ioe.getMessage());
            remoteContent =null;
        }catch(StringIndexOutOfBoundsException stre){
            log.warn("getFromRemote: StringIndexOutOfBoundsException=" + stre.getMessage());
            log.warn("getFromRemote: uri=" + uri );
            log.warn(stre.getMessage());
            remoteContent =null;
        }

        clearCookies();

        log.debug("getFromRemote: remoteContent=\n" + remoteContent);
        // any exception will return "null"
        return remoteContent;
    }
64644
public static function PathConfigList () {
		return [
			//==============================================
			//一般設定
			//==============================================
			'PHP_BINDIR'		=> PHP_BINDIR,
			'BOOT_MODE'			=> Environment::IsCli() ? 'cli' : 'web',

			//==============================================
			//アプリ設定
			//==============================================
			'SYSTEM_ROOT_DIR'		=> Flywheel::GetSystemRootPath(),
			'SRC_DIR'				=> Flywheel::GetSrcPath(),
			'VENDOR_DIR'			=> Flywheel::GetVendorPath(),
			'PACKAGE_DIR'			=> Flywheel::GetPackageFullPath(),
			'APP_DIR'				=> Flywheel::GeAppFullPath(),

			'VENDOR_NAME'			=> Flywheel::GetVendorName(),
			'PACKAGE_NAME'			=> Flywheel::GetPackageName(),
			'CALL_TYPE'				=> Flywheel::GetCallType(),
			'APP_NAME'				=> Flywheel::GetAppName(),

			'PACKAGE_NS_PATH'		=> static::GetPackageNsPath(),
			'COMMONS_NS_PATH'		=> static::GetCommonsNsPath(),
			'APP_NS_PATH'			=> static::GetAppNsPath(),

			'SRC_DIR'				=> static::GetSrcDir(),
			'CONF_DIR'				=> static::GetConfDir(),
			'PASSWORD_DIR'			=> static::GetPasswordDir(),

			'VAR_DIR'				=> static::GetVarDir(),
			'AUTH_DIR'				=> static::GetAuthDir(),
			'CACHE_DIR'				=> static::GetCacheDir(),
			'LOG_DIR'				=> static::GetLogDir(),
			'SESSION_DIR'			=> static::GetSessionDir(),
			'PHP_UPLOAD_TMP_DIR'	=> PhpIni::Get(PhpIni::UPLOAD_TMP_DIR),
			'TMP_DIR'				=> static::GetTmpDir(),

			'APP_CACHE_DIR'			=> static::GetAppCacheDir(),

			'FW2_DEFAULTS_DIR'		=> Flywheel::GetVendorPath() . '/ickx/fw2/mvc/defaults',
		];
	}
107735
public List<Integer> commonPrefixSearch(String key, int pos, int len, int nodePos)
    {
        if (len <= 0)
            len = key.length();
        if (nodePos <= 0)
            nodePos = 0;

        List<Integer> result = new ArrayList<Integer>();

        char[] keyChars = key.toCharArray();

        int b = base[nodePos];
        int n;
        int p;

        for (int i = pos; i < len; i++)
        {
            p = b + (int) (keyChars[i]) + 1;    // 状态转移 p = base[char[i-1]] + char[i] + 1
            if (b == check[p])                  // base[char[i-1]] == check[base[char[i-1]] + char[i] + 1]
                b = base[p];
            else
                return result;
            p = b;
            n = base[p];
            if (b == check[p] && n < 0)         // base[p] == check[p] && base[p] < 0 查到一个词
            {
                result.add(-n - 1);
            }
        }

        return result;
    }
237821
@Override
	protected void initServer(TServerTransport serverTransport) {
		ThriftServerConfiguration configuration = getServerConfiguration();
		// 使用多线程半同步半异步方式
		TThreadedSelectorServer.Args args = new TThreadedSelectorServer.Args((TNonblockingServerSocket) serverTransport)
				.transportFactory(configuration.getTransportFactory())
				.protocolFactory(configuration.getProtocolFactory());
		if (configuration.getExecutorService() != null)
			args.executorService(configuration.getExecutorService());
		server = new TThreadedSelectorServer(
				configuration.getServerArgsAspect().tThreadedSelectorServerArgsAspect(args).processor(getProcessor()));
		if (configuration.getServerEventHandler() != null)
			server.setServerEventHandler(configuration.getServerEventHandler());
	}
79211
private List<String> getDirFilePaths(String xmlPackage, URL url) {
        try {
            return DefaultVfs.newInstance().list(url, xmlPackage);
        } catch (Exception e) {
            // 此处忽略异常堆栈信息.
            log.error("解析zealot xml包存在些问题,将被忽略！xml包为:" + xmlPackage + ",url:" + url);
            return Collections.emptyList();
        }
    }
1084606
public void destroyThriftConnectionPartition(ThriftConnectionPartition<T> thriftConnectionPartition) {
		try {
			serverListLock.writeLock().lock();
			// 首先移除分区信息
			partitions.remove(thriftConnectionPartition);
			thriftConnectionPartition.stopThreads();
			ThriftServerInfo thriftServerInfo = thriftConnectionPartition.getThriftServerInfo();
			thriftServers.remove(thriftServerInfo);
			thriftServerCount = partitions.size();
			logger.info("连接池移除服务器信息：" + thriftServerInfo.getHost() + " 端口:" + thriftServerInfo.getPort());
			if (getThriftServerCount() == 0) {
				logger.error("当前连接池中无可用服务器  无法获取新的客户端连接");
			}
		} finally {
			serverListLock.writeLock().unlock();
		}
		List<ThriftConnectionHandle<T>> clist = new LinkedList<>();
		thriftConnectionPartition.getFreeConnections().drainTo(clist);
		for (ThriftConnectionHandle<T> c : clist) {
			destroyConnection(c);
		}
	}
1041612
function (resourcePath, ext) {
            var self = this;
            var staticPath;
            if (_.isEmpty(self.map)) {
                // map 为空时, 直接拼接路径, 并确保文件存在
                staticPath = FileLoader.matchFile(path.join(self.staticPath, resourcePath) + ext);
                if (staticPath) {
                    staticPath = staticPath.substr(staticPath.indexOf(self.staticFolder));
                }
            } else {
                var resourceKey = resourcePath + ext;
                var result = self.map['res'] && self.map['res'][resourceKey];
                staticPath = result && result.uri;
            }
            return staticPath;
        }
763030
private static boolean isVMMultidexCapable() {
        boolean isMultidexCapable = false;
        String vmName = null;

        try {
            if (isYunOS()) {    // YunOS需要特殊判断
                vmName = "'YunOS'";
                isMultidexCapable = Integer.valueOf(System.getProperty("ro.build.version.sdk")) >= 21;
            } else {    // 非YunOS原生Android
                vmName = "'Android'";
                String versionString = System.getProperty("java.vm.version");
                if (versionString != null) {
                    Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString);
                    if (matcher.matches()) {
                        try {
                            int major = Integer.parseInt(matcher.group(1));
                            int minor = Integer.parseInt(matcher.group(2));
                            isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR)
                                    || ((major == VM_WITH_MULTIDEX_VERSION_MAJOR)
                                    && (minor >= VM_WITH_MULTIDEX_VERSION_MINOR));
                        } catch (NumberFormatException ignore) {
                            // let isMultidexCapable be false
                        }
                    }
                }
            }
        } catch (Exception ignore) {

        }

        Log.i(Consts.TAG, "VM with name " + vmName + (isMultidexCapable ? " has multidex support" : " does not have multidex support"));
        return isMultidexCapable;
    }
1247202
public void init() throws WatchException{
		//获取目录或文件路径
		if(false ==Files.exists(this.path, LinkOption.NOFOLLOW_LINKS)) {
			final Path lastPathEle = FileUtil.getLastPathEle(this.path);
			if(null != lastPathEle) {
				final String lastPathEleStr = lastPathEle.toString();
				//带有点表示有扩展名，按照未创建的文件对待。Linux下.d的为目录，排除之
				if(StrUtil.contains(lastPathEleStr, StrUtil.C_DOT) && false ==StrUtil.endWithIgnoreCase(lastPathEleStr, ".d")) {
					this.filePath = this.path;
					this.path = this.filePath.getParent();
				}
			}
			
			//创建不存在的目录或父目录
			try {
				Files.createDirectories(this.path);
			} catch (IOException e) {
				throw new IORuntimeException(e);
			}
		}else if(Files.isRegularFile(this.path, LinkOption.NOFOLLOW_LINKS)){
			this.filePath = this.path;
			this.path = this.filePath.getParent();
		}
		
		//初始化监听
		try {
			watchService = FileSystems.getDefault().newWatchService();
		} catch (IOException e) {
			throw new WatchException(e);
		}
		
		isClosed = false;
	}
250295
public LinkedList<Map.Entry<String, V>> commonPrefixSearchWithValue(char[] keyChars, int begin)
    {
        int len = keyChars.length;
        LinkedList<Map.Entry<String, V>> result = new LinkedList<Map.Entry<String, V>>();
        int b = base[0];
        int n;
        int p;

        for (int i = begin; i < len; ++i)
        {
            p = b;
            n = base[p];
            if (b == check[p] && n < 0)         // base[p] == check[p] && base[p] < 0 查到一个词
            {
                result.add(new AbstractMap.SimpleEntry<String, V>(new String(keyChars, begin, i - begin), v[-n - 1]));
            }

            p = b + (int) (keyChars[i]) + 1;    // 状态转移 p = base[char[i-1]] + char[i] + 1
            // 下面这句可能产生下标越界，不如改为if (p < size && b == check[p])，或者多分配一些内存
            if (b == check[p])                  // base[char[i-1]] == check[base[char[i-1]] + char[i] + 1]
                b = base[p];
            else
                return result;
        }

        p = b;
        n = base[p];

        if (b == check[p] && n < 0)
        {
            result.add(new AbstractMap.SimpleEntry<String, V>(new String(keyChars, begin, len - begin), v[-n - 1]));
        }

        return result;
    }
819614
function() {
                // 获取现有颜色映射
                //     resource => color_index
                var colorMapping = this._getResourceColorIndexMapping();

                var resource, used, i;

                used = [];

                // 抽取已经使用的值到 used 数组
                for (resource in colorMapping) {
                    if (Object.prototype.hasOwnProperty.call(colorMapping, resource)) {
                        used.push(colorMapping[resource]);
                    }
                }

                // 枚举所有的可用值，如果还没被使用，返回
                for (i = 0; i < RESOURCE_COLOR_SERIES.length; i++) {
                    if (!~used.indexOf(i)) return i;
                }

                // 没有可用的颜色了
                return -1;
            }
1023355
protected function initViewResolvePaths()
    {
        $this->viewResolvePaths = $this->config->get('http_server.view_paths', [
            APP_DIR.'/Views'
        ]);

        // 框架自带的视图目录.
        $this->viewResolvePaths[] = $this->MSFSrcDir.'/Views';
    }
609309
public boolean addThriftServer(ThriftServerInfo thriftServerInfo) throws ThriftConnectionPoolException {
		serverListLock.writeLock().lock();
		try {
			// 验证服务器是否可用
			try {
				ThriftConnection<T> connection = obtainRawInternalConnection(thriftServerInfo);
				connection.close();
			} catch (Exception e) {
				logger.error("无法添加Thrfit服务器到连接池 ip:" + thriftServerInfo.getHost() + " 端口：" + thriftServerInfo.getPort(),
						e);
				return false;
			}
			ThriftConnectionPartition<T> thriftConnectionPartition = createThriftConnectionPartition(thriftServerInfo);

			partitions.add(thriftConnectionPartition);
			thriftServers.add(thriftServerInfo);
			thriftServerCount = partitions.size();
			return true;
		} catch (Exception e) {
			logger.error("无法添加Thrfit服务器到连接池 ip:" + thriftServerInfo.getHost() + " 端口：" + thriftServerInfo.getPort(), e);
			return false;
		} finally {
			serverListLock.writeLock().unlock();
		}
	}
156449
private static void initEngine() {
		engine.setDevMode(constants.getDevMode());
		
		// 避免在某些环境下 webRootPath 值为 blank 时无法启动项目
		if (StrKit.notBlank(PathKit.getWebRootPath())) {
			engine.setBaseTemplatePath(PathKit.getWebRootPath());
		}
	}
520903
public function getSrv()
    {
        if ($this->srv) {
            return $this->srv;
        }

        $this->srv = new \wf\app\ServiceLocator();

        // 框架组件从配置文件注入服务定位器
        $srvCfgs = cfg('srv');
        if (!$srvCfgs) {
            return $this->srv;
        }

        foreach ($srvCfgs as $srvKey => $srvArgs) {
            if (isset($srvArgs['class'])) {
                $isShare = !isset($srvArgs['srvShare']) || $srvArgs['srvShare'] ? true : false;
                $this->srv->set($srvKey, $srvArgs['class'], [$srvArgs], $isShare);
            } else {
                foreach ($srvArgs as $subKey => $subSrvArgs) {
                    if (empty($subSrvArgs['class'])) {
                        continue;
                    }
                    $isShare = !isset($subSrvArgs['srvShare']) || $subSrvArgs['srvShare'] ? true : false;
                    $this->srv->set("{$srvKey}.{$subKey}", $subSrvArgs['class'], [$subSrvArgs], $isShare);
                }
            }
        }

        return $this->srv;
    }
570816
public boolean removeThriftServer(ThriftServerInfo thriftServerInfo) {
		// 不存在这台服务器 直接返回失败
		if (!thriftServers.contains(thriftServerInfo)) {
			return false;
		}

		serverListLock.writeLock().lock();
		try {
			Iterator<ThriftConnectionPartition<T>> iterator = partitions.iterator();
			while (iterator.hasNext()) {
				ThriftConnectionPartition<T> thriftConnectionPartition = iterator.next();
				if (thriftConnectionPartition.getThriftServerInfo().equals(thriftServerInfo)) {
					thriftConnectionPartition.setUnableToCreateMoreTransactions(false);
					List<ThriftConnectionHandle<T>> clist = new LinkedList<>();
					thriftConnectionPartition.getFreeConnections().drainTo(clist);
					for (ThriftConnectionHandle<T> c : clist) {
						destroyConnection(c);
					}
					thriftConnectionPartition.stopThreads();
					partitions.remove(thriftConnectionPartition);
					thriftServers.remove(thriftServerInfo);
					thriftServerCount = partitions.size();
					logger.info("移除服务器操作完成 剩余服务器数量：" + getThriftServerCount());
					if (getThriftServerCount() == 0) {
						logger.warn("连接池中没有可用thrift服务器 无法获取连接");
					}
					return true;
				}
			}
		} catch (Exception e) {
			logger.error("移除Thrift服务器失败  ip:" + thriftServerInfo.getHost() + " 端口：" + thriftServerInfo.getPort());
			return false;
		} finally {
			serverListLock.writeLock().unlock();
		}
		return false;
	}
881490
@Override
    public StorePath uploadImage(FastImageFile fastImageFile) {
        String fileExtName = fastImageFile.getFileExtName();
        Validate.notNull(fastImageFile.getInputStream(), "上传文件流不能为空");
        Validate.notBlank(fileExtName, "文件扩展名不能为空");
        // 检查是否能处理此类图片
        if (!isSupportImage(fileExtName)) {
            throw new FdfsUnsupportImageTypeException("不支持的图片格式" + fileExtName);
        }
        // 获取存储节点
        StorageNode client = getStorageNode(fastImageFile.getGroupName());
        byte[] bytes = inputStreamToByte(fastImageFile.getInputStream());

        // 上传文件和metaDataSet
        StorePath path = uploadFileAndMetaData(client, new ByteArrayInputStream(bytes),
                fastImageFile.getFileSize(), fileExtName,
                fastImageFile.getMetaDataSet());

        //如果设置了需要上传缩略图
        if (null != fastImageFile.getThumbImage()) {
            // 上传缩略图
            uploadThumbImage(client, new ByteArrayInputStream(bytes), path.getPath(), fastImageFile);
        }
        bytes = null;
        return path;
    }