JcrExportCommand filter to exclude "mgnl:page" in magnolia cms - magnolia

I would like filter out "mgnl:page" nodes for the JcrExportCommand in magnolia when I execute it on a node with a custom action.
The filter I wrote in the code below doesn't work. It still gives me mgnl:page children nodes in the exported file.
//set filter to only export mgnl:area subnodes
DefaultFilter filter = new JcrExportCommand.DefaultFilter();
NodeFilteringPredicate nodePredicate = new NodeFilteringPredicate();
nodePredicate.setNodeTypes(Lists.newArrayList("mgnl:area"));
filter.setNodePredicate(nodePredicate);
How do I set the correct filter to export everything but "mgnl:page" subnodes? I believed that setting the NodeFilteringPredicate to "mgnl:area" I get only nodes that are of that type.

You have to set the filter on JcrExportCommand for it to take effect:
DefaultFilter filter = new DefaultFilter();
filter.getNodePredicate().getNodeTypes().add("mgnl:page");
jcrExport.setFilter(Collections.singletonMap("website", filter));

* this is not the answer to my question but instead the answer to a comment since code is not properly formated in a comment *
As #michid suggested I created a custom Predicator and used JcrExportCommand.DefaultFilter#setNodePredicate()to apply it.
I am expecting to get an exported YAML with filtered nodes according to the Predicate but instead I am still getting all the nodes (including children of type mgnl:page).
My custom Predicate class is:
public class MyPredicate extends NodeFilteringPredicate {
public boolean evaluate(Node node) throws AccessDeniedException, ItemNotFoundException, RepositoryException {
//only nodes that are not of type mgnl:page
if((node.getParent().getPrimaryNodeType().getName().contains("mgnl:page"))&&(node.getPrimaryNodeType().getName().contains("mgnl:page"))) {
return false;
}else{
return true;
}
}
}
My custom Action class is:
public class MyAction extends AbstractMultiItemAction<UzhVersioning> {
private AbstractPredicate<Node> MyPredicate;
public MyAction(xxxVersioning definition, JcrItemAdapter item, UiContext uiContext) {
super(definition, item, uiContext);
// TODO Auto-generated constructor stub
}
#Override
public void execute() {
//export nodes from a JCR workspace
JcrExportCommand exporter = new JcrExportCommand();
//sets export format to yaml
exporter.setFormat("yaml");
exporter.setRepository("website");
//set filter to only export top mgnl:page and its mgnl:area nodes
DefaultFilter filter = new JcrExportCommand.DefaultFilter();
AbstractPredicate<Node> predicate = new MyPredicate();
filter.setNodePredicate(predicate);
exporter.setFilters(Collections.singletonMap("website", filter));
//setup the root directory for exports
File rootDir = new File("/Users/asusti/Downloads/yamlExport");
// clean up first
rootDir.delete();
rootDir.mkdirs();
//get root node
Node node = (Node) getItems().get(0).getJcrItem();
try {
//set export path
exporter.setPath(node.getPath());
File file = new File(rootDir, node.getName()+".yaml");
FileOutputStream out = new FileOutputStream(file);
exporter.setOutputStream(out);
exporter.execute(MgnlContext.getInstance());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Related

With OpenCSV, how do I append to existing CSV using a MappingStrategy?

With OpenCSV, how do I append to existing CSV using a MappingStrategy? There are lots of examples I could find where NOT using a Bean mapping stategy BUT I like the dynamic nature of the column mapping with bean strategy and would like to get it working this way. Here is my code, which just rewrites the single line to CSV file instead of appending.
How can I fix this? Using OpenCSV 4.5 . Note: I set my FileWriter for append=true . This scenario is not working as I expected. Re-running this method simply results in over-writing the entire file with a header and a single row.
public void addRowToCSV(PerfMetric rowData) {
File file = new File(PerfTestMetric.CSV_FILE_PATH);
try {
CSVWriter writer = new CSVWriter(new FileWriter(file, true));
CustomCSVMappingStrategy<PerfMetric> mappingStrategy
= new CustomCSVMappingStrategy<>();
mappingStrategy.setType(PerfMetric.class);
StatefulBeanToCsv<PerfMetric> beanToCsv
= new StatefulBeanToCsvBuilder<PerfMetric>(writer)
.withMappingStrategy(mappingStrategy)
.withSeparator(',')
.withApplyQuotesToAll(false)
.build();
try {
beanToCsv.write(rowData);
} catch (CsvDataTypeMismatchException e) {
e.printStackTrace();
} catch (CsvRequiredFieldEmptyException e) {
e.printStackTrace();
}
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Or, is the usual pattern to load all rows into a List and then re-write entire file? I was able to get it to work by writing two MappingStrategy mapping strategies and then conditionally using them with a if-file-exists but doing it that way leaves me with a "Unchecked assignment" warning in my code. Not ideal; hoping for an elegant solution?
I've updated OpenCSV to version 5.1 and got it working. In my case I needed the CSV headers to have a specific name and position, so I'm using both #CsvBindByName and #CsvBindByPosition, and needed to create a custom MappingStrategy to get it working.
Later, I needed to edit the MappingStrategy to enable appending, so when it's in Appending mode I don't need to generate a CSV header.
public class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
private boolean useHeader=true;
public CustomMappingStrategy(){
}
public CustomMappingStrategy(boolean useHeader) {
this.useHeader = useHeader;
}
#Override
public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
final int numColumns = FieldUtils.getAllFields(bean.getClass()).length;
super.setColumnMapping(new String[numColumns]);
if (numColumns == -1) {
return super.generateHeader(bean);
}
String[] header = new String[numColumns];
if(!useHeader){
return ArrayUtils.EMPTY_STRING_ARRAY;
}
BeanField<T, Integer> beanField;
for (int i = 0; i < numColumns; i++){
beanField = findField(i);
String columnHeaderName = extractHeaderName(beanField);
header[i] = columnHeaderName;
}
return header;
}
private String extractHeaderName(final BeanField<T, Integer> beanField){
if (beanField == null || beanField.getField() == null || beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class).length == 0){
return StringUtils.EMPTY;
}
//return value of CsvBindByName annotation
final CsvBindByName bindByNameAnnotation = beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class)[0];
return bindByNameAnnotation.column();
}
}
Now if you use the default constructor it'll add the header to the generated CSV, and using a boolean you can tell it to add a header or to ignore it.
I never found an answer to this question and so what I ended up doing was doing a branch if-condition where .csv file exists or not. If file exists I used MappingStrategyWithoutHeader strategy, and if file didn't yet exist, I used MappingStrategyWithHeader strategy. Not ideal, but I got it working.

AspectJ - Is is possible to extend an enum's value?

Say I have an enum
public enum E {A,B,C}
Is it possible to add another value, say D, by AspectJ?
After googling around, it seems that there used to be a way to hack the private static field $VALUES, then call the constructor(String, int) by reflection, but seems not working with 1.7 anymore.
Here are several links:
http://www.javaspecialists.eu/archive/Issue161.html (provided by #WimDeblauwe )
and this: http://www.jroller.com/VelkaVrana/entry/modify_enum_with_reflection
Actually, I recommend you to refactor the source code, maybe adding a collection of valid region IDs to each enumeration value. This should be straightforward enough for subsequent merging if you use Git and not some old-school SCM tool like SVN.
Maybe it would even make sense to use a dynamic data structure altogether instead of an enum if it is clear that in the future the list of commands is dynamic. But that should go into the upstream code base. I am sure the devs will accept a good patch or pull request if prepared cleanly.
Remember: Trying to avoid refactoring is usually a bad smell, a symptom of an illness, not a solution. I prefer solutions to symptomatic workarounds. Clean code rules and software craftsmanship attitude demand that.
Having said the above, now here is what you can do. It should work under JDK 7/8 and I found it on Jérôme Kehrli's blog (please be sure to add the bugfix mentioned in one of the comments below the article).
Enum extender utility:
package de.scrum_master.util;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import sun.reflect.ConstructorAccessor;
import sun.reflect.FieldAccessor;
import sun.reflect.ReflectionFactory;
public class DynamicEnumExtender {
private static ReflectionFactory reflectionFactory =
ReflectionFactory.getReflectionFactory();
private static void setFailsafeFieldValue(Field field, Object target, Object value)
throws NoSuchFieldException, IllegalAccessException
{
// let's make the field accessible
field.setAccessible(true);
// next we change the modifier in the Field instance to
// not be final anymore, thus tricking reflection into
// letting us modify the static final field
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(field);
// blank out the final bit in the modifiers int
modifiers &= ~Modifier.FINAL;
modifiersField.setInt(field, modifiers);
FieldAccessor fa = reflectionFactory.newFieldAccessor(field, false);
fa.set(target, value);
}
private static void blankField(Class<?> enumClass, String fieldName)
throws NoSuchFieldException, IllegalAccessException
{
for (Field field : Class.class.getDeclaredFields()) {
if (field.getName().contains(fieldName)) {
AccessibleObject.setAccessible(new Field[] { field }, true);
setFailsafeFieldValue(field, enumClass, null);
break;
}
}
}
private static void cleanEnumCache(Class<?> enumClass)
throws NoSuchFieldException, IllegalAccessException
{
blankField(enumClass, "enumConstantDirectory"); // Sun (Oracle?!?) JDK 1.5/6
blankField(enumClass, "enumConstants"); // IBM JDK
}
private static ConstructorAccessor getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes)
throws NoSuchMethodException
{
Class<?>[] parameterTypes = new Class[additionalParameterTypes.length + 2];
parameterTypes[0] = String.class;
parameterTypes[1] = int.class;
System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);
return reflectionFactory.newConstructorAccessor(enumClass .getDeclaredConstructor(parameterTypes));
}
private static Object makeEnum(Class<?> enumClass, String value, int ordinal, Class<?>[] additionalTypes, Object[] additionalValues)
throws Exception
{
Object[] parms = new Object[additionalValues.length + 2];
parms[0] = value;
parms[1] = Integer.valueOf(ordinal);
System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);
return enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms));
}
/**
* Add an enum instance to the enum class given as argument
*
* #param <T> the type of the enum (implicit)
* #param enumType the class of the enum to be modified
* #param enumName the name of the new enum instance to be added to the class
*/
#SuppressWarnings("unchecked")
public static <T extends Enum<?>> void addEnum(Class<T> enumType, String enumName) {
// 0. Sanity checks
if (!Enum.class.isAssignableFrom(enumType))
throw new RuntimeException("class " + enumType + " is not an instance of Enum");
// 1. Lookup "$VALUES" holder in enum class and get previous enum
// instances
Field valuesField = null;
Field[] fields = enumType.getDeclaredFields();
for (Field field : fields) {
if (field.getName().contains("$VALUES")) {
valuesField = field;
break;
}
}
AccessibleObject.setAccessible(new Field[] { valuesField }, true);
try {
// 2. Copy it
T[] previousValues = (T[]) valuesField.get(enumType);
List<T> values = new ArrayList<T>(Arrays.asList(previousValues));
// 3. build new enum
T newValue = (T) makeEnum(
enumType, // The target enum class
enumName, // THE NEW ENUM INSTANCE TO BE DYNAMICALLY ADDED
values.size(), new Class<?>[] {}, // could be used to pass values to the enum constuctor if needed
new Object[] {} // could be used to pass values to the enum constuctor if needed
);
// 4. add new value
values.add(newValue);
// 5. Set new values field
setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(enumType, 0)));
// 6. Clean enum cache
cleanEnumCache(enumType);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e);
}
}
}
Sample application & enum:
package de.scrum_master.app;
/** In honour of "The Secret of Monkey Island"... ;-) */
public enum Command {
OPEN, CLOSE, PUSH, PULL, WALK_TO, PICK_UP, TALK_TO, GIVE, USE, LOOK_AT, TURN_ON, TURN_OFF
}
package de.scrum_master.app;
public class Server {
public void executeCommand(Command command) {
System.out.println("Executing command " + command);
}
}
package de.scrum_master.app;
public class Client {
private Server server;
public Client(Server server) {
this.server = server;
}
public void issueCommand(String command) {
server.executeCommand(
Command.valueOf(
command.toUpperCase().replace(' ', '_')
)
);
}
public static void main(String[] args) {
Client client = new Client(new Server());
client.issueCommand("use");
client.issueCommand("walk to");
client.issueCommand("undress");
client.issueCommand("sleep");
}
}
Console output with original enum:
Executing command USE
Executing command WALK_TO
Exception in thread "main" java.lang.IllegalArgumentException: No enum constant de.scrum_master.app.Command.UNDRESS
at java.lang.Enum.valueOf(Enum.java:236)
at de.scrum_master.app.Command.valueOf(Command.java:1)
at de.scrum_master.app.Client.issueCommand(Client.java:12)
at de.scrum_master.app.Client.main(Client.java:22)
Now you can either add an aspect with an advice executed after the enum class was loaded or just call this manually in your application before extended enum values are to be used for the first time. Here I am showing how it can be done in an aspect.
Enum extender aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.Command;
import de.scrum_master.util.DynamicEnumExtender;
public aspect CommandExtender {
after() : staticinitialization(Command) {
System.out.println(thisJoinPoint);
DynamicEnumExtender.addEnum(Command.class, "UNDRESS");
DynamicEnumExtender.addEnum(Command.class, "SLEEP");
DynamicEnumExtender.addEnum(Command.class, "WAKE_UP");
DynamicEnumExtender.addEnum(Command.class, "DRESS");
}
}
Console output with extended enum:
staticinitialization(de.scrum_master.app.Command.<clinit>)
Executing command USE
Executing command WALK_TO
Executing command UNDRESS
Executing command SLEEP
Et voilà! ;-)

Retrieve property by name

I'm struggling to create a dynamic view generation utility for javafx. I've a handful of Classes that have ObjectProperty's or StringProperty's I'd like to create a ComboBox for each property and bind directly the combo selected value to the Class property by name if possible. Is there some helper or method in any of the javafx.beans.binding that would allow me to specify an Object and a String name and retrieve the property. Or to just retrieve a list of properties. I have a method now that takes the string and matches it to the property by name but it requires I have a case for each property on the object, which on an object with 20+ properties is a lot of duplicate code.
I guess to specify I'm looking for javafx.bean.property as a return type.
You can always use Java Reflection.
Getting a list of properties
for (Method method : Node.class.getMethods()) {
String name = method.getName();
if (name.endsWith("Property")) {
Type returnType = method.getReturnType();
String propName = name.replace("Property", "");
System.out.println(propName + " : " + returnType);
}
}
Here is reflective method for binding and example:
public class ReflectiveBind extends Application {
/**
* Reflection call for code like
* slider1.valueProperty().bindBidirectional(slider2.valueProperty());
*
* #param bindee Node which you want to be changed by binding
* #param propertyName name of the property, e.g. width
* #param bindTarget Node which you want to be updated by binding
*/
private static void bind(Object bindee, String propertyName, Object bindTarget) throws Exception {
// here we get slider1.valueProperty()
Method methodForBindee = bindee.getClass().getMethod(propertyName + "Property", (Class[]) null);
Object bindableObj = methodForBindee.invoke(bindee);
// here we get slider2.valueProperty()
Method methodForBindTarget = bindTarget.getClass().getMethod(propertyName + "Property", (Class[]) null);
Object bindTargetObj = methodForBindTarget.invoke(bindTarget);
// here we call bindBidirectional: slider1.valueProperty().bindBidirectional(slider2.valueProperty())
Method bindMethod = bindableObj.getClass().getMethod("bindBidirectional", Property.class);
bindMethod.invoke(bindableObj, bindTargetObj);
}
#Override
public void start(Stage stage) {
Slider slider1 = new Slider();
Slider slider2 = new Slider();
VBox root = new VBox(20);
root.getChildren().addAll(slider1, slider2);
stage.setScene(new Scene(root, 200, 100));
stage.show();
try {
//same call as slider1.valueProperty().bindBidirectional(slider2.valueProperty());
bind(slider1, "value", slider2);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) { launch(); }
}
Check out apache commons bean utils
http://commons.apache.org/beanutils/
You say you want to...
Get the value of the property:
http://commons.apache.org/beanutils/api/org/apache/commons/beanutils/BeanUtils.html#getProperty%28java.lang.Object,%20java.lang.String%29
Get List of Properties:
http://commons.apache.org/beanutils/api/org/apache/commons/beanutils/BeanUtils.html#describe%28java.lang.Object%29
Lots of other useful methods there, and for UI work they are particularly convenient since many of them return the string form which is what you want to display.
If you want objects rather than strings use the PropertUtils class instead
Get the value of the property (not as a string)
http://commons.apache.org/beanutils/v1.8.3/apidocs/org/apache/commons/beanutils/PropertyUtils.html#getProperty%28java.lang.Object,%20java.lang.String%29
Get list of properties:
http://commons.apache.org/beanutils/v1.8.3/apidocs/org/apache/commons/beanutils/PropertyUtils.html#describe%28java.lang.Object%29

Execute flow each time a custom event is fired

I need to execute Show created file name each time Watch files fires an event
WatchFilesActivity : NativeActivity
protected override void Execute(NativeActivityContext context)
{
var fileSystemWatcher = new FileSystemWatcher(context.GetValue(Path));
fileSystemWatcher.IncludeSubdirectories = context.GetValue(IncludeSubdirectories);
fileSystemWatcher.Filter = context.GetValue(Filter);
var bookmark = context.CreateBookmark(ResumeFileCreatedBookmark);
context.GetExtension<FileSystemWatcherExtension>().Start(fileSystemWatcher, bookmark);
}
Extension
public class FileSystemWatcherExtension : IWorkflowInstanceExtension
{
WorkflowInstanceProxy instance;
Bookmark bookmark;
public void SetInstance(WorkflowInstanceProxy instance)
{
this.instance = instance;
}
IEnumerable<object> IWorkflowInstanceExtension.GetAdditionalExtensions()
{
yield break;
}
public void Start(FileSystemWatcher fileSystemWatcher, Bookmark bookmark)
{
this.bookmark = bookmark;
fileSystemWatcher.Created += new FileSystemEventHandler(FileCreated);
fileSystemWatcher.EnableRaisingEvents = true;
}
void FileCreated(object sender, FileSystemEventArgs e)//When the file arrives
{
instance.BeginResumeBookmark(bookmark, e.FullPath, CompleteResume, null);
}
void CompleteResume(IAsyncResult ar)
{
var result = instance.EndResumeBookmark(ar);
}
}
This is working great, but only once, and after this the host closes.
I can't put a WhileActivity because I need to handle consecutive very fast file creations and the processing time of an incoming file(Show created file name, in this case) is greater than the file creation rate
Thanks!
For a starter I would make the Show created file name activity a child activity of the Watch files activity so it can control it's execution. Next I would add a bookmark resumption callback so Watch files activity can react to and schedule the Show created file name activity in the callback.
Optionally you might want to create your bookmark with BookmarkOptions.MultipleResume so you can handle as many file events as you want and only move on when you want to do so.
public class WatchFilesActivity : NativeActivity
{
public Activity Child {get; set;}
protected override void Execute(NativeActivityContext context)
{
var fileSystemWatcher = new FileSystemWatcher(context.GetValue(Path));
fileSystemWatcher.IncludeSubdirectories = context.GetValue(IncludeSubdirectories);
fileSystemWatcher.Filter = context.GetValue(Filter);
var bookmark = context.CreateBookmark(ResumeFileCreatedBookmark, OnFileCreated, BookmarkOptions.MultipleResume);
context.GetExtension<FileSystemWatcherExtension>().Start(fileSystemWatcher, bookmark);
}
protected void OnFileCreated(NativeActivityContext context, Bookmark bookmark, object value)
{
var fileName = (string)value
context.ScheduleActivity(Child);
}
}
Note: Code typed in Notepad so possible typos.
If you need to pass the file name on to the child activity you can use an ActivityAction to do just that. See here for an example using an ActivityFunc which is just like an ActivityAction except it also has a return value.

Elegant way to bind html radio buttons <=> Java enums <=> mysql enums in Play?

The Goal is to have a list of options (that a user can chose through radio buttons) in one place(for eg: a yaml config file). No other place should have this list hard-coded
I've done something similar to create select elements, and I think enums worked just fine. Doing radio buttons should be very similar. I've set it up so that the labels can be defined in the messages file. I'm going to try to excerpt the relevant portions from my larger auto-form-generation code (using FastTags) the best I can. It's a bit heavy for this one case but it makes sense in the larger system.
I use the tag like #{form.selector 'order.status' /}, which looks find the variable named order in the template, sees that status is declared as public Status status, and then goes to find all the values of the Status enum and generate options for them in the select element.
First, I use a FieldContext object which just contains a bunch of info that's used by the other code to determine what to generate along with some utility methods:
public class FieldContext {
public final Map<?,?> args;
public final ExecutableTemplate template;
public final int fromLine;
public Class clazz = null;
public Field field = null;
public Object object = null;
public Object value = null;
private Map<String,String> attrs = new HashMap<String,String>();
private Map<String,Boolean> printed = new HashMap<String,Boolean>();
private List<Option> options;
...
Then I have this in another helper class (its info gets added to the FieldContext):
public List<Option> determineOptions(FieldContext context) {
List<Option> options = new ArrayList<Option>();
if (context.field.getType().isEnum()) {
for (Object option : context.field.getType().getEnumConstants()) {
options.add(new Option(option.toString(), Message.get(option.toString())));
}
}
return options;
}
then the tag declaration is
public static void _selector(Map<?,?> args, Closure body, PrintWriter out, ExecutableTemplate template, int fromLine) {
String field_name = args.get("arg").toString();
TagContext.current().data.put("name", field_name);
SelectHelper helper = HelperFactory.getHelper(SelectHelper.class);
try {
FieldContext context = new FieldContext(field_name, args, template, fromLine);
helper.autoconfigure(context);
TagContext.current().data.put("selected", helper.determineValue(context));
out.print("<div class=\"formutil-field formutil-selector\">");
out.print("<label for=\"" + context.getAttr("id") + "\">");
out.print(helper.findOrCreateLabel(context));
out.print("</label>");
out.print("<select");
context.printAttribute(out, "id", "name");
out.print(">");
if (context.hasOptions()) {
for (Option option : context.getOptions()) {
out.print("<option value=\"" + option.value + "\">" + option.label + "</option>");
}
}
out.print("</select>");
context.printErrorIfPresent(out);
context.printValidationHints(out);
out.println("</div>");
}
...
}

Resources