package org.jbehave.eclipse.preferences; import static org.jbehave.eclipse.preferences.ClassScannerFilterEntry.filter; import static org.jbehave.eclipse.preferences.ClassScannerFilterEntry.toPatterns; import static org.jbehave.eclipse.preferences.ClassScannerFilterEntry.toSplittedPatterns; import static org.jbehave.eclipse.util.FJ.listCollector; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.zip.Adler32; import org.apache.commons.lang.StringUtils; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; import org.eclipse.core.runtime.preferences.IScopeContext; import org.jbehave.eclipse.Activator; import org.jbehave.eclipse.preferences.ClassScannerFilterEntry.ApplyOn; import org.jbehave.eclipse.util.Bytes; import org.jbehave.eclipse.util.StringMatcher; import org.osgi.service.prefs.BackingStoreException; import fj.Effect; import fj.data.List; public class ClassScannerPreferences { private static final String QUALIFIER = Activator.PLUGIN_ID + "/classScanner"; public static final String EXCLUDE_SUFFIX = "-excludes"; public static final String INCLUDE_SUFFIX = "-includes"; // public static final String USE_PROJECT_SETTINGS = "use_project_settings"; private final PreferencesHelper helper; private List<ClassScannerFilterEntry> entries = List.nil(); private boolean useProjectSettings; public ClassScannerPreferences(IScopeContext scope) { helper = PreferencesHelper.getHelper(QUALIFIER, scope); } public ClassScannerPreferences() { helper = PreferencesHelper.getHelper(QUALIFIER); } public ClassScannerPreferences(final IProject project) { helper = PreferencesHelper.getHelper(QUALIFIER, project); } public void addListener(IPreferenceChangeListener changeListener) { helper.addListener(changeListener); } public StringMatcher getPackageRootMatcher() { StringMatcher m = new StringMatcher(); m.addGlobExcludes(getPackageRootExcludes()); m.addGlobIncludes(getPackageRootIncludes()); return m; } public String[] getPackageRootExcludes() { return getSplittedStrings(ApplyOn.PackageRoot, true); } public String[] getPackageRootIncludes() { return getSplittedStrings(ApplyOn.PackageRoot, false); } public StringMatcher getPackageMatcher() { StringMatcher m = new StringMatcher(); m.addGlobExcludes(getPackageExcludes()); m.addGlobIncludes(getPackageIncludes()); return m; } public String[] getPackageExcludes() { return getSplittedStrings(ApplyOn.Package, true); } public String[] getPackageIncludes() { return getSplittedStrings(ApplyOn.Package, false); } public StringMatcher getClassMatcher() { StringMatcher m = new StringMatcher(); m.addGlobExcludes(getClassExcludes()); m.addGlobIncludes(getClassIncludes()); return m; } public String[] getClassExcludes() { return getSplittedStrings(ApplyOn.Class, true); } public String[] getClassIncludes() { return getSplittedStrings(ApplyOn.Class, false); } private String[] getSplittedStrings(ApplyOn applyOn, boolean exclude) { List<String> patterns = entries .filter(filter(applyOn, exclude)) .map(toSplittedPatterns()) .foldLeft(listCollector(String.class), List.<String>nil()); return patterns.toArray().array(String[].class); } public boolean hasOptionsAtLowestScope() { return helper.hasAnyAtLowestScope(); } public void store() throws BackingStoreException { helper.removeAllAtLowestScope(); boolean[] modes = { true, false }; for(ApplyOn applyOn : ApplyOn.values()) { for(Boolean mode : modes) { List<String> patternsList = entries.filter(filter(applyOn, mode)).map(toPatterns()); String value = StringUtils.join(patternsList.toCollection(), "|"); String key = applyOn + (mode?EXCLUDE_SUFFIX:INCLUDE_SUFFIX); helper.putString(key, value); } } helper.putBoolean(USE_PROJECT_SETTINGS, useProjectSettings); helper.flush(); } public void load() throws BackingStoreException { boolean[] modes = { true, false }; entries = List.nil(); for(ApplyOn applyOn : ApplyOn.values()) { for(Boolean mode : modes) { String key = applyOn + (mode?EXCLUDE_SUFFIX:INCLUDE_SUFFIX); String inlinedPatterns = helper.getString(key, ""); for(String patterns : inlinedPatterns.split("[\\|]")) { if(StringUtils.isBlank(patterns)) continue; entries = entries.snoc(new ClassScannerFilterEntry(patterns, applyOn, mode)); } } } useProjectSettings = helper.getBoolean(USE_PROJECT_SETTINGS, false); } public ClassScannerFilterEntry addEntry(String patterns, ApplyOn applyOn, boolean exclude) { ClassScannerFilterEntry entry = new ClassScannerFilterEntry(patterns, applyOn, exclude); if(entries.exists(entry.equalF())) return null; entries = entries.snoc(entry); return entry; } public void removeEntry(ClassScannerFilterEntry entry) { entries = entries.removeAll(entry.equalF()); } public List<ClassScannerFilterEntry> getEntries() { return entries; } public boolean isUseProjectSettings() { return useProjectSettings; } public void setUseProjectSettings(boolean useProjectSettings) { this.useProjectSettings = useProjectSettings; } public void removeAllSpecificSettings() throws BackingStoreException { helper.removeAllAtLowestScope(); load(); } public Object[] getEntriesAsObjectArray() { return entries.toCollection().toArray(); } public byte[] calculateHash() { try { final MessageDigest md = MessageDigest.getInstance("MD5"); entries.foreach(new Effect<ClassScannerFilterEntry>() { final byte[] bytes = new byte[2]; @Override public void e(ClassScannerFilterEntry entry) { bytes[0] = (byte) (entry.getApplyOn().ordinal()); bytes[1] = (byte) (entry.isExclude()?1:0); md.update(bytes); md.update(entry.getPatterns().getBytes()); } }); return md.digest(); } catch (NoSuchAlgorithmException e1) { final Adler32 adler32 = new Adler32(); entries.foreach(new Effect<ClassScannerFilterEntry>() { final byte[] bytes = new byte[2]; @Override public void e(ClassScannerFilterEntry entry) { bytes[0] = (byte) (entry.getApplyOn().ordinal()); bytes[1] = (byte) (entry.isExclude()?1:0); adler32.update(bytes); adler32.update(entry.getPatterns().getBytes()); } }); return Bytes.longToBytes(adler32.getValue()); } } }