/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.sshd.server;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.apache.sshd.common.channel.PtyMode;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class StandardEnvironment extends AbstractLoggingBean implements Environment {
private final Map<Signal, Collection<SignalListener>> listeners;
private final Map<String, String> env;
private final Map<PtyMode, Integer> ptyModes;
public StandardEnvironment() {
listeners = new ConcurrentHashMap<>(3);
env = new ConcurrentHashMap<>();
ptyModes = new ConcurrentHashMap<>();
}
@Override
public void addSignalListener(SignalListener listener, Signal... signals) {
addSignalListener(listener, Arrays.asList(ValidateUtils.checkNotNullAndNotEmpty(signals, "No signals")));
}
@Override
public void addSignalListener(SignalListener listener) {
addSignalListener(listener, Signal.SIGNALS);
}
/*
* NOTE: we don't care if the collection is a Set or not - after all,
* we hold the listeners inside a Set, so even if we add several times
* the same listener to the same signal set, it is harmless
*/
@Override
public void addSignalListener(SignalListener listener, Collection<Signal> signals) {
SignalListener.validateListener(listener);
ValidateUtils.checkNotNullAndNotEmpty(signals, "No signals");
for (Signal s : signals) {
getSignalListeners(s, true).add(listener);
}
}
@Override
public Map<String, String> getEnv() {
return env;
}
@Override
public Map<PtyMode, Integer> getPtyModes() {
return ptyModes;
}
@Override
public void removeSignalListener(SignalListener listener) {
if (listener == null) {
return;
}
SignalListener.validateListener(listener);
for (Signal s : Signal.SIGNALS) {
Collection<SignalListener> ls = getSignalListeners(s, false);
if (ls != null) {
ls.remove(listener);
}
}
}
public void signal(Signal signal) {
Collection<SignalListener> ls = getSignalListeners(signal, false);
if (log.isDebugEnabled()) {
log.debug("signal({}) - listeners={}", signal, ls);
}
if (GenericUtils.isEmpty(ls)) {
return;
}
for (SignalListener l : ls) {
try {
l.signal(signal);
if (log.isTraceEnabled()) {
log.trace("Signal {} to {}", signal, l);
}
} catch (RuntimeException e) {
log.warn("Failed ({}) to signal {} to listener={}: {}",
e.getClass().getSimpleName(), signal, l, e.getMessage());
}
}
}
/**
* Adds a variable to the environment. This method is called <code>set</code>
* according to the name of the appropriate posix command <code>set</code>
*
* @param key environment variable name - never {@code null}/empty
* @param value environment variable value
*/
public void set(String key, String value) {
// TODO: listening for property changes would be nice too.
getEnv().put(ValidateUtils.checkNotNullAndNotEmpty(key, "Empty environment variable name"), value);
}
/**
* Retrieves the set of listeners registered for a signal
*
* @param signal The specified {@link Signal}
* @param create If {@code true} and no current listeners are mapped then
* creates a new {@link Collection}
* @return The {@link Collection} of listeners registered for the signal - may be
* {@code null} in case <tt>create</tt> is {@code false}
*/
protected Collection<SignalListener> getSignalListeners(Signal signal, boolean create) {
Collection<SignalListener> ls = listeners.get(signal);
if ((ls == null) && create) {
synchronized (listeners) {
ls = listeners.get(signal);
if (ls == null) {
ls = new CopyOnWriteArraySet<>();
listeners.put(signal, ls);
}
}
}
return ls;
}
@Override
public String toString() {
return "env=" + getEnv() + ", modes=" + getPtyModes();
}
}