package act.sys;
/*-
* #%L
* ACT Framework
* %%
* Copyright (C) 2014 - 2017 ActFramework
* %%
* 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.
* #L%
*/
import act.Act;
import org.osgl.util.C;
import org.osgl.util.OS;
import org.osgl.util.S;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.annotation.*;
import java.lang.management.ManagementFactory;
import java.lang.reflect.AnnotatedElement;
/**
* Mark a module should only be loaded in certain environment
*/
public final class Env {
private Env() {}
/**
* Used to mark a dependency injector module that
* should be load only in specified profile.
*
* This annotation shall NOT used along with
* {@link Mode} and {@link Group}
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Profile {
/**
* The profile specification
*/
String value();
/**
* If unless is `true` then the module should be load
* unless the current profile is the value specified
*/
boolean unless() default false;
}
/**
* Used to mark a dependency injector module that
* should be load only in specified node group
*
* This annotation shall NOT used along with
* {@link Mode} and {@link Profile}
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Group {
/**
* The node group specification
*/
String value();
/**
* If unless is `true` then the module should be load
* unless the current node group is the value specified
*/
boolean unless() default false;
}
/**
* Used to mark a dependency injector module
* that should be load only in specified mode
*
* This annotation shall NOT used along with
* {@link Profile} and {@link Group}
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Mode {
/**
* The mode specification
*/
Act.Mode value();
/**
* If unless is `true` then the module should be load
* unless the current mode is the value specified
*/
boolean unless() default false;
}
public static boolean matches(Mode modeTag) {
return modeMatches(modeTag.value(), modeTag.unless());
}
public static boolean modeMatches(Act.Mode mode) {
return mode == Act.mode();
}
public static boolean modeMatches(Act.Mode mode, boolean unless) {
return unless ^ modeMatches(mode);
}
public static boolean matches(Profile profileTag) {
return profileMatches(profileTag.value(), profileTag.unless());
}
public static boolean profileMatches(String profile) {
return S.eq(profile, Act.profile(), S.IGNORECASE);
}
public static boolean profileMatches(String profile, boolean unless) {
return unless ^ profileMatches(profile);
}
public static boolean matches(Group groupTag) {
return groupMatches(groupTag.value(), groupTag.unless());
}
public static boolean groupMatches(String group) {
return S.eq(group, Act.nodeGroup(), S.IGNORECASE);
}
public static boolean groupMatches(String group, boolean unless) {
return unless ^ groupMatches(group);
}
private static final C.Set<Class<? extends Annotation>> ENV_ANNOTATION_TYPES = C.set(
Env.Mode.class, Env.Profile.class, Env.Group.class
);
public static boolean isEnvAnnotation(Class<? extends Annotation> type) {
return ENV_ANNOTATION_TYPES.contains(type);
}
/**
* Determine if an {@link AnnotatedElement} has environment annotations and if it has then check
* if all environment annotations matches the current executing environment
* @param annotatedElement an annotated element
* @return `true` if the element does not have environment annotations or all environment annotations matches
*/
public static boolean matches(AnnotatedElement annotatedElement) {
Annotation[] annotations = annotatedElement.getDeclaredAnnotations();
for (Annotation anno : annotations) {
if (anno instanceof Profile) {
Profile profile = (Profile)anno;
if (!matches(profile)) {
return false;
}
} else if (anno instanceof Group) {
Group group = (Group) anno;
if (!matches(group)) {
return false;
}
} else if (anno instanceof Mode) {
Mode mode = (Mode) anno;
if (!matches(mode)) {
return false;
}
}
}
return true;
}
// See http://stackoverflow.com/questions/534648/how-to-daemonize-a-java-program
public static class PID {
private static String pid = getPid();
private static String getPid() {
OS os = OS.get();
if (os.isUnix()) {
File proc_self = new File("/proc/self");
if(proc_self.exists()) try {
return proc_self.getCanonicalFile().getName();
}
catch(Exception e) {
/// Continue on fall-back
}
File bash = new File("/bin/sh");
if(bash.exists()) {
ProcessBuilder pb = new ProcessBuilder("/bin/sh","-c","echo $PPID");
try {
Process p = pb.start();
BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()));
return rd.readLine();
}
catch(IOException e) {
return String.valueOf(Thread.currentThread().getId());
}
}
} else {
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
if (null != nameOfRunningVM) {
int p = nameOfRunningVM.indexOf('@');
if (p > -1) {
return nameOfRunningVM.substring(0, p);
}
}
}
// The final resort
return String.valueOf(Thread.currentThread().getId());
}
public static String get() {
return pid;
}
}
}