How to Improve Problem Solving Skills
April 24, 2019
Jeffery Yuan
April 24, 2019
earliest=“11/5/2017:20:00:00” latest=“11/12/2017:20:00:00”
| table field
NOT fa=*
| top a_number SourceName
ast -n2 -x shutdown reboot
host $ip
@Data
@Accessors(chain = true)
@EqualsAndHashCode(of = {"employeeId"}, callSuper = false)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "employeeId")
public static class Employee {
private UUID employeeId;
private String name;
private Department department;
}
@Data
@Accessors(chain = true)
@EqualsAndHashCode(of = {"departmentId"}, callSuper = false)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "departmentId")
@ToString(exclude = "employees")
private static class Department {
private UUID departmentId;
private String name;
private Set<Employee> employees;
public Set<Employee> getEmployees() {
if (employees == null) {
employees = new HashSet<>();
}
return employees;
}
}
public static void main(String[] args) throws IOException {
Employee e1 = new Employee().setEmployeeId(UUID.randomUUID()).setName("e1");
Department d1 =
new Department().setDepartmentId(UUID.randomUUID()).setName("oldD1").setEmployees(Sets.newHashSet(e1));
e1.setDepartment(d1);
ObjectMapper objectMapper = new ObjectMapper();
String departmentStr = objectMapper.writeValueAsString(d1);
objectMapper.writeValueAsString(e1);
Department oldD1 = objectMapper.readValue(departmentStr, Department.class);
Department newD1 = new Department().setDepartmentId(d1.getDepartmentId()).setName("newD1");
newD1.getEmployees().addAll(oldD1.getEmployees());
// without the following statements: it will throw
// com.fasterxml.jackson.databind.JsonMappingException: Already had POJO for id
// for (Employee e : oldD1.getEmployees()) {
// e.setDepartment(newD1);
// }
departmentStr = objectMapper.writeValueAsString(newD1);
System.out.println("new department: " + departmentStr);
// now read it back will throw sonMappingException: Already had POJO for id
Department newNewD1 = objectMapper.readValue(departmentStr, Department.class);
System.out.println("---" + newNewD1);
}
This reproduces the issue, and from the output:
// without the following statements: it will throw
// com.fasterxml.jackson.databind.JsonMappingException: Already had POJO for id
for (Employee e : oldD1.getEmployees()) {
e.setDepartment(newD1);
}
static {
if (!ClassUtils.isPresent("org.junit.internal.Throwables", SpringJUnit4ClassRunner.class.getClassLoader())) {
throw new IllegalStateException("SpringJUnit4ClassRunner requires JUnit 4.12 or higher.");
}
withRulesMethod = ReflectionUtils.findMethod(SpringJUnit4ClassRunner.class, "withRules",
FrameworkMethod.class, Object.class, Statement.class);
if (withRulesMethod == null) {
throw new IllegalStateException("SpringJUnit4ClassRunner requires JUnit 4.12 or higher.");
}
ReflectionUtils.makeAccessible(withRulesMethod);
}
private Description describeCause(Throwable child) {
return Description.createTestDescription(fTestClass,
"initializationError");
}
@Nonnull private List<Future<List<T>>> findAllAsync(final SolrParams originalParams, final int readSize,
final long totalCount) {
final ModifiableSolrParams query = new ModifiableSolrParams(originalParams);
query.set(CommonParams.ROWS, readSize);
final List<Future<List<T>>> futures = new ArrayList<>();
int start = 0;
while (start < totalCount) {
final ModifiableSolrParams solrParams = new ModifiableSolrParams(query);
solrParams.set(CommonParams.START, start);
final Stopwatch stopWatch = Stopwatch.createStarted();
futures.add(executor.submit(() -> querySolr(solrParams)));
if (logger.isDebugEnabled()) {
logger.debug(MessageFormat.format("executor.submit took {0}, params: {1}",
stopWatch.elapsed(TimeUnit.MILLISECONDS), solrParams));
}
start += readSize;
}
return futures;
}
public interface FeatureService {
Decision isFeatureOn(String name, Map<String, Object> variables);
public Optional<Feature> getFeature(final String name);
public void addFeature(Feature feature);
public void updateFeature(Feature feature);
void deleteFeature(Iterator<String> iterator);
Collection<Feature> getAllFeatures();
}
public class Feature {
private String name;
private String appId;
/**
* This is used as extension, in case later we support rejectFirst.
*/
private boolean acceptFirst = true;
public Feature() {}
@JsonView(View.Editable.class)
private List<Expression> expressionList = new ArrayList<>();
@JsonView(View.Editable.class)
protected int ttlSeconds = -1;
@JsonView(View.Viewable.class) // all other properties are marked as Editable, except updateTime
private Date updateTime;
@JsonIgnore
public boolean isEffective() {
if (ttlSeconds != -1) {
if (updateTime == null) {
logger.error("Invalid feature {}, updateTime is null while timeToLive is {}", name, ttlSeconds);
throw new XXException(ErrorCode.INTERNAL_ERROR,
String.format("Invalid feature %s: ", getName()));
}
final MutableDateTime expiredTime = new MutableDateTime(updateTime);
expiredTime.addSeconds(ttlSeconds);
return expiredTime.isAfterNow();
}
return true;
}
public Decision isFeatureOn(final Map<String, String> variables) {
if (hasExpired()) {
return Decision.NEUTRAL;
}
final List<Expression> expressionList = getExpressionList();
for (final Expression expression : expressionList) {
if (expression.apply(variables).equals(Decision.ACCEPT)) {
return Decision.ACCEPT;
}
}
return Decision.NEUTRAL;
}
// ignore equals, hashcode, toString, getter, setter..
}
@JsonIgnoreProperties(ignoreUnknown = true)
@org.codehaus.jackson.annotate.JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = AbstractExpression.FIELD_TYPE,
visible = false)
@JsonSubTypes({@Type(value = PercentageExpression.class, name = PercentageExpression.TYPE),
@Type(value = AnyMatchExpression.class, name = AnyMatchExpression.TYPE),
@Type(value = ScriptExpression.class, name = ScriptExpression.TYPE)})
public interface Expression {
public Decision apply(Map<String, Object> variables);
}
public class AnyMatchExpression extends AbstractExpression {
public static final String TYPE = "anyMatch";
/**
* which variable name to look up
*/
private String variableName;
private boolean caseInsensitive;
@JsonProperty("set")
private Set<String> set = new HashSet<>();
public AnyMatchExpression() {
type = TYPE;
}
@Override
public Decision apply(final Map<String, Object> variables) {
final Object object = variables.get(variableName);
if (object != null) {
final Iterable<String> idIt = SomeUtil.COMMA_SPLITTER.split(object.toString());
for (String id : idIt) {
if (caseInsensitive) {
id = id.toLowerCase();
}
if (set.contains(id)) {
return Decision.ACCEPT;
}
}
}
return Decision.NEUTRAL;
}
/**
* Precondition: There is no null value in the set. Otherwise it will throw NPE.
*/
public void setSet(final HashSet<String> set) {
if (caseInsensitive) {
final HashSet<String> lowercaseSet = new HashSet<>();
for (final String word : set) {
lowercaseSet.add(word.toLowerCase());
}
this.set = lowercaseSet;
} else {
this.set = set;
}
}
// ignore toString, getter, setter..
}
public class PercentageExpression extends AbstractExpression {
public static final String TYPE = "percentage";
/**
* a value between 0 and 100
*/
private int percentage;
public PercentageExpression() {
type = TYPE;
}
@Override
public Decision apply(final Map<String, Object> variables) {
if (percentage == 100) {
return Decision.ACCEPT;
}
final Random random = new Random();
final int rValue = random.nextInt(100);
if (rValue < percentage) {
return Decision.ACCEPT;
}
return Decision.REJECT;
}
}
protected void checkDebugRequestFeature(final ContainerRequest request) {
if (debugRequestEnabled) {
final String debugRequest = request.getHeaderValue(X_DEBUG_REQUEST);
if (StringUtils.isNotBlank(debugRequest)) {
final User user = getUserObjectHere();
if (SomeUtil.isFeatureOn(SomeUtil.FEATURE_DEBUG_REQUEST, user, featureService)) {
MDC.put(X_DEBUG_REQUEST, debugRequest);
RequestContextUtil.getRequestContext().setEnableDebug(Boolean.valueOf(debugRequest));
} else {
RequestContextUtil.getRequestContext().setEnableDebug(false);
}
}
}
}
Other User Cases Using Feature Toggle{
"data": { // here it can be an object(for getById) or an array(for query)
}
"diagnosis": [] // list of string that may help diagnose the problem
// here can be some pagination meta data
}
public class PerRequestTurboFilter extends DynamicThresholdFilter {
@Override
public FilterReply decide(final Marker marker, final Logger logger, final Level level, final String s,
final Object[] objects, final Throwable throwable) {
final String loggerName = logger.getName();
if (loggerName.startsWith("com.myapp") || loggerName.startsWith("org.apache.http")
|| loggerName.startsWith("httpclient.wire")) {
return super.decide(marker, logger, level, s, objects, throwable);
}
addMesToRequestConext(reply, loggerName, msg);
return FilterReply.NEUTRAL;
}
protected void addMesToRequestConext(final FilterReply reply, final String loggerName, final String msg,) {
final String mdcValue = MDC.get(getKey());
if (mdcValue != null && reply.equals(FilterReply.ACCEPT) && StringUtils.isNotBlank(msg)
&& loggerName.startsWith("com.myapp")) {
RequestContextUtil.getRequestContext().addDiagnosis(msg);
}
}
}
PerRequestTurboFilter extends Logback DynamicThresholdFilter, it will only change logger level for com.app and apache http and httpclient. If MDC contains X-Debug-Request, and its value is true, the filter will accept the log request.<turboFilter class="com.myapp.PerRequestTurboFilter"> <Key>X-Debug-Request</Key> <OnHigherOrEqual>ACCEPT</OnHigherOrEqual> <OnLower>NEUTRAL</OnLower> <MDCValueLevelPair> <value>true</value> <level>DEBUG</level> </MDCValueLevelPair> </turboFilter>
@Provider
@Component
public class HttpHeaderFilter implements ContainerRequestFilter, ContainerResponseFilter {
public static final String X_DEBUG_REQUEST = "X-Debug-Request";
private static final String X_DEBUG_KEY = "X-DEBUG-KEY";
// Used to protect debug header, we can change it from property file.
@Value("${debug.key:}")
private String debugKey;
@Context
HttpServletRequest servletRequest;
@Override
public ContainerRequest filter(final ContainerRequest request) {
setLogDiagnosticContextParams(request);
return request;
}
private void setLogDiagnosticContextParams(final ContainerRequest request) {
final String debugRequest = request.getHeaderValue(X_DEBUG_REQUEST);;
if (debugRequest != null) {
final String clientKey = request.getHeaderValue(X_DEBUG_KEY);
if (debugKey.equals(clientKey)) {
MDC.put(X_DEBUG_REQUEST, debugRequest);
RequestContextUtil.getRequestContext().setEnableDebug(Boolean.valueOf(debugRequest));
} else {
RequestContextUtil.getRequestContext().setEnableDebug(false);
}
}
}
@Override
public ContainerResponse filter(final ContainerRequest request, final ContainerResponse response) {
final MultivaluedMap<String, Object> headers = response.getHttpHeaders();
final Object entity = response.getEntity();
if (RequestContextUtil.getRequestContext().isEnableDebug()) {
if (entity instanceof ClientData) {
final ClientData<?> clientData = (ClientData<?>) entity;
clientData.add(ClientData.DIAGNOSIS, RequestContextUtil.getRequestContext().getDiagnosises());
} else {
headers.add(ClientData.DIAGNOSIS, RequestContextUtil.getRequestContext().getDiagnosises());
}
}
clear();
return response;
}
private void clear() {
MDC.clear();
RequestContextUtil.removeRequestContext();
}
}
public class RequestContextUtil {
private static ThreadLocal<RequestContext> requestContextLocal = new ThreadLocal<RequestContext>() {
protected RequestContext initialValue() {
return new RequestContext();
};
};
public static ThreadLocal<RequestContext> getRequestContextLocal() {
return requestContextLocal;
}
public static void setRequestContext(final RequestContext userContext) {
requestContextLocal.set(userContext);
}
public static RequestContext getRequestContext() {
return requestContextLocal.get();
}
public static void removeRequestContext() {
requestContextLocal.remove();
}
public static class RequestContext implements Serializable {
private static final long serialVersionUID = 1L;
private boolean enableDebug;
final List<String> diagnosises = new ArrayList<>();
public List<String> getDiagnosises() {
return diagnosises;
}
public void addDiagnosis(final String diagnosis) {
diagnosises.add(diagnosis);
}
public boolean isEnableDebug() {
return enableDebug;
}
public void setEnableDebug(final boolean enableDebug) {
this.enableDebug = enableDebug;
}
}
}