mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[git] Refactor git-ssh architecture: generify
Rename GitSSHService to GitXmlRpcHandlerService and let it be the base abstract class parametrized by the actual GUI handler. Move SSH-specific code to the first implementation: GitXmlRpcSshService.
This commit is contained in:
@@ -149,8 +149,8 @@
|
||||
serviceInterface="git4idea.history.wholeTree.GitCommitsSequentially"/>
|
||||
<applicationService serviceInterface="git4idea.config.GitVcsApplicationSettings"
|
||||
serviceImplementation="git4idea.config.GitVcsApplicationSettings"/>
|
||||
<applicationService serviceInterface="org.jetbrains.git4idea.ssh.GitSSHService"
|
||||
serviceImplementation="org.jetbrains.git4idea.ssh.GitSSHService"/>
|
||||
<applicationService serviceInterface="org.jetbrains.git4idea.ssh.GitXmlRpcSshService"
|
||||
serviceImplementation="org.jetbrains.git4idea.ssh.GitXmlRpcSshService"/>
|
||||
<applicationService serviceInterface="git4idea.rebase.GitRebaseEditorService"
|
||||
serviceImplementation="git4idea.rebase.GitRebaseEditorService"/>
|
||||
<applicationService serviceInterface="git4idea.config.SSHConnectionSettings"
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
@@ -39,7 +40,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.git4idea.ssh.GitSSHHandler;
|
||||
import org.jetbrains.git4idea.ssh.GitSSHService;
|
||||
import org.jetbrains.git4idea.ssh.GitXmlRpcSshService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
@@ -418,7 +419,7 @@ public abstract class GitHandler {
|
||||
|
||||
// setup environment
|
||||
if (myRemoteProtocol == GitRemoteProtocol.SSH && myProjectSettings.isIdeaSsh()) {
|
||||
GitSSHService ssh = GitSSHService.getInstance();
|
||||
GitXmlRpcSshService ssh = ServiceManager.getService(GitXmlRpcSshService.class);
|
||||
myEnv.put(GitSSHHandler.GIT_SSH_ENV, ssh.getScriptPath().getPath());
|
||||
myHandlerNo = ssh.registerHandler(new GitSSHGUIHandler(myProject, myState));
|
||||
myEnvironmentCleanedUp = false;
|
||||
@@ -490,7 +491,7 @@ public abstract class GitHandler {
|
||||
*/
|
||||
protected synchronized void cleanupEnv() {
|
||||
if (myRemoteProtocol == GitRemoteProtocol.SSH && !myEnvironmentCleanedUp) {
|
||||
GitSSHService ssh = GitSSHService.getInstance();
|
||||
GitXmlRpcSshService ssh = ServiceManager.getService(GitXmlRpcSshService.class);
|
||||
myEnvironmentCleanedUp = true;
|
||||
ssh.unregisterHandler(myHandlerNo);
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.git4idea.ssh;
|
||||
|
||||
import com.intellij.ide.XmlRpcServer;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.trilead.ssh2.KnownHosts;
|
||||
import git4idea.commands.GitSSHGUIHandler;
|
||||
import gnu.trove.THashMap;
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.xmlrpc.XmlRpcClientLite;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.git4idea.util.ScriptGenerator;
|
||||
import org.jetbrains.ide.WebServerManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* The provider of SSH scripts for the Git
|
||||
*/
|
||||
public class GitSSHService {
|
||||
|
||||
/**
|
||||
* random number generator to use
|
||||
*/
|
||||
private static final Random RANDOM = new Random();
|
||||
/**
|
||||
* Path to the generated script
|
||||
*/
|
||||
private File myScriptPath;
|
||||
/**
|
||||
* Registered handlers
|
||||
*/
|
||||
private final THashMap<Integer, GitSSHGUIHandler> handlers = new THashMap<Integer, GitSSHGUIHandler>();
|
||||
|
||||
@NotNull
|
||||
public static GitSSHService getInstance() {
|
||||
return ServiceManager.getService(GitSSHService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the port number for XML RCP
|
||||
*/
|
||||
public int getXmlRcpPort() {
|
||||
return WebServerManager.getInstance().waitForStart().getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file to the script service
|
||||
*
|
||||
* @return path to the script
|
||||
* @throws IOException if script cannot be generated
|
||||
*/
|
||||
@NotNull
|
||||
public synchronized File getScriptPath() throws IOException {
|
||||
if (myScriptPath == null || !myScriptPath.exists()) {
|
||||
ScriptGenerator generator = new ScriptGenerator(GitSSHHandler.GIT_SSH_PREFIX, SSHMain.class, getTempDir());
|
||||
generator.addClasses(XmlRpcClientLite.class, DecoderException.class, KnownHosts.class, FileUtilRt.class);
|
||||
generator.addResource(SSHMainBundle.class, "/org/jetbrains/git4idea/ssh/SSHMainBundle.properties");
|
||||
myScriptPath = generator.generate();
|
||||
}
|
||||
return myScriptPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the temporary directory to use or null if the default directory might be used
|
||||
*/
|
||||
@SuppressWarnings({"MethodMayBeStatic"})
|
||||
@Nullable
|
||||
protected File getTempDir() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register handler. Note that handlers must be unregistered using {@link #unregisterHandler(int)}.
|
||||
*
|
||||
* @param handler a handler to register
|
||||
* @return an identifier to pass to the environment variable
|
||||
*/
|
||||
public synchronized int registerHandler(@NotNull GitSSHGUIHandler handler) {
|
||||
XmlRpcServer xmlRpcServer = XmlRpcServer.SERVICE.getInstance();
|
||||
if (!xmlRpcServer.hasHandler(GitSSHHandler.HANDLER_NAME)) {
|
||||
xmlRpcServer.addHandler(GitSSHHandler.HANDLER_NAME, new InternalRequestHandler());
|
||||
}
|
||||
|
||||
while (true) {
|
||||
int candidate = RANDOM.nextInt();
|
||||
if (candidate == Integer.MIN_VALUE) {
|
||||
continue;
|
||||
}
|
||||
candidate = Math.abs(candidate);
|
||||
if (handlers.containsKey(candidate)) {
|
||||
continue;
|
||||
}
|
||||
handlers.put(candidate, handler);
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get handler for the key
|
||||
*
|
||||
* @param key the key to use
|
||||
* @return the registered handler
|
||||
*/
|
||||
@NotNull
|
||||
private synchronized GitSSHGUIHandler getHandler(int key) {
|
||||
GitSSHGUIHandler rc = handlers.get(key);
|
||||
if (rc == null) {
|
||||
throw new IllegalStateException("No handler for the key " + key);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister handler by the key
|
||||
*
|
||||
* @param key the key to unregister
|
||||
*/
|
||||
public synchronized void unregisterHandler(int key) {
|
||||
if (handlers.remove(key) == null) {
|
||||
throw new IllegalArgumentException("The handler " + key + " is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal handler implementation class, do not use it.
|
||||
*/
|
||||
public class InternalRequestHandler implements GitSSHHandler {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean verifyServerHostKey(final int handler,
|
||||
final String hostname,
|
||||
final int port,
|
||||
final String serverHostKeyAlgorithm,
|
||||
final String serverHostKey,
|
||||
final boolean isNew) {
|
||||
return getHandler(handler).verifyServerHostKey(hostname, port, serverHostKeyAlgorithm, serverHostKey, isNew);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String askPassphrase(final int handler,
|
||||
final String username,
|
||||
final String keyPath,
|
||||
final boolean resetPassword,
|
||||
final String lastError) {
|
||||
return adjustNull(getHandler(handler).askPassphrase(username, keyPath, resetPassword, lastError));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@SuppressWarnings({"UseOfObsoleteCollectionType"})
|
||||
public Vector<String> replyToChallenge(final int handlerNo,
|
||||
final String username,
|
||||
final String name,
|
||||
final String instruction,
|
||||
final int numPrompts,
|
||||
final Vector<String> prompt,
|
||||
final Vector<Boolean> echo,
|
||||
final String lastError) {
|
||||
return adjustNull(getHandler(handlerNo).replyToChallenge(username, name, instruction, numPrompts, prompt, echo, lastError));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String askPassword(final int handlerNo, final String username, final boolean resetPassword, final String lastError) {
|
||||
return adjustNull(getHandler(handlerNo).askPassword(username, resetPassword, lastError));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String setLastSuccessful(int handlerNo, String userName, String method, String error) {
|
||||
getHandler(handlerNo).setLastSuccessful(userName, method, error);
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getLastSuccessful(int handlerNo, String userName) {
|
||||
return getHandler(handlerNo).getLastSuccessful(userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust null value ({@code "-"} if null, {@code "+"+s) if non-null)
|
||||
*
|
||||
* @param s a value to adjust
|
||||
* @return adjusted string
|
||||
*/
|
||||
private String adjustNull(final String s) {
|
||||
return s == null ? "-" : "+" + s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust null value (returns empty array)
|
||||
*
|
||||
* @param s if null return empty array
|
||||
* @return s if not null, empty array otherwise
|
||||
*/
|
||||
@SuppressWarnings({"UseOfObsoleteCollectionType"})
|
||||
private <T> Vector<T> adjustNull(final Vector<T> s) {
|
||||
return s == null ? new Vector<T>() : s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.git4idea.ssh;
|
||||
|
||||
import com.intellij.ide.XmlRpcServer;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import gnu.trove.THashMap;
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.xmlrpc.XmlRpcClientLite;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.git4idea.util.ScriptGenerator;
|
||||
import org.jetbrains.ide.WebServerManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* <p>The provider of external application scripts called by Git when a remote operation needs communication with the user.</p>
|
||||
* <p>
|
||||
* Usage:
|
||||
* <ol>
|
||||
* <li>Get the script from {@link #getScriptPath()}.</li>
|
||||
* <li>Set up proper environment variable
|
||||
* (e.g. {@code GIT_SSH} for SSH connections, or {@code GIT_ASKPASS} for HTTP) pointing to the script.</li>
|
||||
* <li>{@link #registerHandler(Object) Register} the handler of Git requests.</li>
|
||||
* <li>Call Git operation.</li>
|
||||
* <li>If the operation requires user interaction, the registered handler is called via XML RPC protocol.
|
||||
* It can show a dialog in the GUI and return the answer via XML RPC to the external application, that further provides
|
||||
* this value to the Git process.</li>
|
||||
* <li>{@link #unregisterHandler(int) Unregister} the handler after operation has completed.</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*/
|
||||
public abstract class GitXmlRpcHandlerService<T> {
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
@Nullable private File myScriptPath;
|
||||
@NotNull private final THashMap<Integer, T> handlers = new THashMap<Integer, T>();
|
||||
|
||||
/**
|
||||
* @return the port number for XML RCP
|
||||
*/
|
||||
public int getXmlRcpPort() {
|
||||
return WebServerManager.getInstance().waitForStart().getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file to the script service
|
||||
*
|
||||
* @return path to the script
|
||||
* @throws IOException if script cannot be generated
|
||||
*/
|
||||
@NotNull
|
||||
public synchronized File getScriptPath() throws IOException {
|
||||
if (myScriptPath == null || !myScriptPath.exists()) {
|
||||
ScriptGenerator generator = new ScriptGenerator(getScriptTempFilePrefix(), getScriptMainClass(), getTempDir());
|
||||
generator.addClasses(XmlRpcClientLite.class, DecoderException.class, FileUtilRt.class);
|
||||
customizeScriptGenerator(generator);
|
||||
myScriptPath = generator.generate();
|
||||
}
|
||||
return myScriptPath;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract String getScriptTempFilePrefix();
|
||||
|
||||
@NotNull
|
||||
protected abstract Class<?> getScriptMainClass();
|
||||
|
||||
/**
|
||||
* Adds more classes or resources to the script if needed.
|
||||
*/
|
||||
protected abstract void customizeScriptGenerator(@NotNull ScriptGenerator generator);
|
||||
|
||||
/**
|
||||
* @return the temporary directory to use or null if the default directory might be used
|
||||
*/
|
||||
@SuppressWarnings({"MethodMayBeStatic"})
|
||||
@Nullable
|
||||
protected File getTempDir() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register handler. Note that handlers must be unregistered using {@link #unregisterHandler(int)}.
|
||||
*
|
||||
* @param handler a handler to register
|
||||
* @return an identifier to pass to the environment variable
|
||||
*/
|
||||
public synchronized int registerHandler(@NotNull T handler) {
|
||||
XmlRpcServer xmlRpcServer = XmlRpcServer.SERVICE.getInstance();
|
||||
if (!xmlRpcServer.hasHandler(getRpcHandlerName())) {
|
||||
xmlRpcServer.addHandler(getRpcHandlerName(), createRpcRequestHandlerDelegate());
|
||||
}
|
||||
|
||||
while (true) {
|
||||
int candidate = RANDOM.nextInt();
|
||||
if (candidate == Integer.MIN_VALUE) {
|
||||
continue;
|
||||
}
|
||||
candidate = Math.abs(candidate);
|
||||
if (handlers.containsKey(candidate)) {
|
||||
continue;
|
||||
}
|
||||
handlers.put(candidate, handler);
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the handler to be used by XML RPC client to call remote methods of a proper object.
|
||||
*/
|
||||
@NotNull
|
||||
protected abstract String getRpcHandlerName();
|
||||
|
||||
/**
|
||||
* Creates an implementation of the xml rpc handler, which methods will be called from the external application.
|
||||
* This method should just delegate the call to the specific handler of type {@link T}, which can be achieved by {@link #getHandler(int)}.
|
||||
* @return New instance of the xml rpc handler delegate.
|
||||
*/
|
||||
@NotNull
|
||||
protected abstract Object createRpcRequestHandlerDelegate();
|
||||
|
||||
/**
|
||||
* Get handler for the key
|
||||
*
|
||||
* @param key the key to use
|
||||
* @return the registered handler
|
||||
*/
|
||||
@NotNull
|
||||
protected synchronized T getHandler(int key) {
|
||||
T rc = handlers.get(key);
|
||||
if (rc == null) {
|
||||
throw new IllegalStateException("No handler for the key " + key);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister handler by the key
|
||||
*
|
||||
* @param key the key to unregister
|
||||
*/
|
||||
public synchronized void unregisterHandler(int key) {
|
||||
if (handlers.remove(key) == null) {
|
||||
throw new IllegalArgumentException("The handler " + key + " is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.git4idea.ssh;
|
||||
|
||||
import com.trilead.ssh2.KnownHosts;
|
||||
import git4idea.commands.GitSSHGUIHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.git4idea.util.ScriptGenerator;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
public class GitXmlRpcSshService extends GitXmlRpcHandlerService<GitSSHGUIHandler> {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getScriptTempFilePrefix() {
|
||||
return GitSSHHandler.GIT_SSH_PREFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeScriptGenerator(@NotNull ScriptGenerator generator) {
|
||||
generator.addClasses(KnownHosts.class);
|
||||
generator.addResource(SSHMainBundle.class, "/org/jetbrains/git4idea/ssh/SSHMainBundle.properties");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<?> getScriptMainClass() {
|
||||
return SSHMain.class;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getRpcHandlerName() {
|
||||
return GitSSHHandler.HANDLER_NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Object createRpcRequestHandlerDelegate() {
|
||||
return new InternalRequestHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal handler implementation class, do not use it.
|
||||
*/
|
||||
public class InternalRequestHandler implements GitSSHHandler {
|
||||
|
||||
@Override
|
||||
public boolean verifyServerHostKey(int handler, String hostname, int port, String serverHostKeyAlgorithm, String serverHostKey,
|
||||
boolean isNew) {
|
||||
return getHandler(handler).verifyServerHostKey(hostname, port, serverHostKeyAlgorithm, serverHostKey, isNew);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String askPassphrase(int handler, String username, String keyPath, boolean resetPassword, String lastError) {
|
||||
return adjustNull(getHandler(handler).askPassphrase(username, keyPath, resetPassword, lastError));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"UseOfObsoleteCollectionType"})
|
||||
public Vector<String> replyToChallenge(int handlerNo, String username, String name, String instruction, int numPrompts,
|
||||
Vector<String> prompt, Vector<Boolean> echo, String lastError) {
|
||||
return adjustNull(getHandler(handlerNo).replyToChallenge(username, name, instruction, numPrompts, prompt, echo, lastError));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String askPassword(int handlerNo, String username, boolean resetPassword, String lastError) {
|
||||
return adjustNull(getHandler(handlerNo).askPassword(username, resetPassword, lastError));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setLastSuccessful(int handlerNo, String userName, String method, String error) {
|
||||
getHandler(handlerNo).setLastSuccessful(userName, method, error);
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastSuccessful(int handlerNo, String userName) {
|
||||
return getHandler(handlerNo).getLastSuccessful(userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust null value ({@code "-"} if null, {@code "+"+s) if non-null)
|
||||
*
|
||||
* @param s a value to adjust
|
||||
* @return adjusted string
|
||||
*/
|
||||
private String adjustNull(final String s) {
|
||||
return s == null ? "-" : "+" + s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust null value (returns empty array)
|
||||
*
|
||||
* @param s if null return empty array
|
||||
* @return s if not null, empty array otherwise
|
||||
*/
|
||||
@SuppressWarnings({"UseOfObsoleteCollectionType"})
|
||||
private <T> Vector<T> adjustNull(final Vector<T> s) {
|
||||
return s == null ? new Vector<T>() : s;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user