Skip to content

Commit bc22b52

Browse files
committed
Encourage optional feature flag names to work as startup props
1 parent 2edbc28 commit bc22b52

6 files changed

Lines changed: 50 additions & 26 deletions

File tree

api/src/org/labkey/api/settings/OptionalFeatureFlag.java

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,47 @@ public class OptionalFeatureFlag implements Comparable<OptionalFeatureFlag>, Sta
1212
private static final Logger LOG = LogHelper.getLogger(OptionalFeatureFlag.class, "Warnings about optional feature flag names");
1313

1414
private final String _flag;
15+
private final String _propertyName;
1516
private final String _title;
1617
private final String _description;
1718
private final boolean _requiresRestart;
1819
private final boolean _hidden;
1920
private final FeatureType _type;
2021

2122
/**
22-
* @param flag must be unique. Can be used as a startup property to enable/disable the task, but only if it follows
23-
* the Java identifier rules (e.g., alphanumeric plus _, start with a letter, no spaces).
23+
* @param flag must be unique and conform to the Java identifier rules (e.g., alphanumeric plus _, start with a
24+
* letter, no spaces). That way it can be used as a startup property to enable/disable the task.
2425
*/
2526
public OptionalFeatureFlag(String flag, String title, String description, boolean requiresRestart, boolean hidden, FeatureType type)
27+
{
28+
this(flag, title, description, requiresRestart, hidden, type, false);
29+
}
30+
31+
OptionalFeatureFlag(String flag, String title, String description, boolean requiresRestart, boolean hidden, FeatureType type, boolean useDumbName /* true means allow a name that can't be used as a startup property name */)
2632
{
2733
_flag = flag;
2834
_title = title;
2935
_description = description;
3036
_requiresRestart = requiresRestart;
3137
_hidden = hidden;
3238
_type = type;
39+
if (!StringUtilsLabKey.isValidJavaIdentifier(_flag))
40+
{
41+
if (useDumbName)
42+
{
43+
_propertyName = null;
44+
}
45+
else
46+
{
47+
// TODO: Switch to throw IllegalStateException
48+
LOG.error(_flag + " is not a valid Java identifier. Correct it so it can be used as a startup property. Or set useDumbName to true.", new IllegalStateException());
49+
_propertyName = null;
50+
}
51+
}
52+
else
53+
{
54+
_propertyName = _flag;
55+
}
3356
}
3457

3558
public String getFlag()
@@ -83,14 +106,6 @@ public FeatureType getType()
83106
@Override
84107
public String getPropertyName()
85108
{
86-
String name = getFlag();
87-
if (!StringUtilsLabKey.isValidJavaIdentifier(name))
88-
{
89-
// This is a developer thing... no need to log a warning on production deployments
90-
if (AppProps.getInstance().isDevMode())
91-
LOG.warn("Feature flag name doesn't conform to the property name rules so it won't be available as a startup property: {}", name);
92-
name = null;
93-
}
94-
return name;
109+
return _propertyName;
95110
}
96111
}

api/src/org/labkey/api/settings/OptionalFeatureService.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,21 @@ static void setInstance(OptionalFeatureService impl)
4343
}
4444

4545
/**
46-
* @param flag must be unique. Can be used as a startup property to enable/disable the task, but only if it follows
47-
* the Java identifier rules (e.g., alphanumeric plus _, start with a letter, no spaces).
46+
* @param flag must be unique and conform to the Java identifier rules (e.g., alphanumeric plus _, start with a
47+
* letter, no spaces). That way it can be used as a startup property to enable/disable the task. If
48+
* you must use a flag that doesn't conform to these rules (why?) the call the other variant.
4849
*/
4950
default void addExperimentalFeatureFlag(String flag, String title, String description, boolean requiresRestart)
5051
{
51-
addFeatureFlag(new OptionalFeatureFlag(flag, title, description, requiresRestart, false, FeatureType.Experimental));
52+
addExperimentalFeatureFlag(flag, title, description, requiresRestart, false);
53+
}
54+
55+
/**
56+
* This is left for backward compatibility. Use the variant above and provide flag that follows Java identifier rules.
57+
*/
58+
default void addExperimentalFeatureFlag(String flag, String title, String description, boolean requiresRestart, boolean useDumbName)
59+
{
60+
addFeatureFlag(new OptionalFeatureFlag(flag, title, description, requiresRestart, false, FeatureType.Experimental, useDumbName));
5261
}
5362

5463
void addFeatureFlag(OptionalFeatureFlag optionalFeatureFlag);

core/src/org/labkey/core/CoreModule.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -529,19 +529,20 @@ public QuerySchema createSchema(DefaultSchema schema, Module module)
529529
}
530530

531531
OptionalFeatureService.get().addExperimentalFeatureFlag(NotificationMenuView.EXPERIMENTAL_NOTIFICATION_MENU, "Notifications Menu",
532-
"Notifications 'inbox' count display in the header bar with click to show the notifications panel of unread notifications.", false);
532+
"Notifications 'inbox' count display in the header bar with click to show the notifications panel of unread notifications.", false, true);
533533
OptionalFeatureService.get().addExperimentalFeatureFlag(DataColumn.EXPERIMENTAL_USE_QUERYSELECT_COMPONENT, "Use QuerySelect for row insert/update form",
534534
"This feature will switch the query based select inputs on the row insert/update form to use the React QuerySelect" +
535535
"component. This will allow for a user to view the first 100 options in the select but then use type ahead" +
536-
"search to find the other select values.", false);
536+
"search to find the other select values.", false, true);
537537
OptionalFeatureService.get().addExperimentalFeatureFlag(SQLFragment.FEATUREFLAG_DISABLE_STRICT_CHECKS, "Disable SQLFragment strict checks",
538-
"SQLFragment now has very strict usage validation, these checks may cause errors in code that has not been updated. Turn on this feature to disable checks.", false);
538+
"SQLFragment now has very strict usage validation, these checks may cause errors in code that has not been updated. Turn on this feature to disable checks.", false, true);
539539
OptionalFeatureService.get().addExperimentalFeatureFlag(LoginController.FEATUREFLAG_DISABLE_LOGIN_XFRAME, "Disable Login X-FRAME-OPTIONS=DENY",
540-
"By default LabKey disables all framing of login related actions. Disabling this feature will revert to using the standard site settings.", false);
540+
"By default LabKey disables all framing of login related actions. Disabling this feature will revert to using the standard site settings.", false, true);
541541
OptionalFeatureService.get().addExperimentalFeatureFlag(PageTemplate.EXPERIMENTAL_SHORT_CIRCUIT_ROBOTS,
542542
"Short-circuit robots",
543543
"Save resources by not rendering pages marked as 'noindex' for robots. This is experimental as not all robots are search engines.",
544-
false);
544+
false,
545+
true);
545546
OptionalFeatureService.get().addExperimentalFeatureFlag(AppProps.REJECT_CONTROLLER_FIRST_URLS,
546547
"Reject controller-first URLs",
547548
"Require standard path-first URLs.",

devtools/src/org/labkey/devtools/DevtoolsModule.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import org.labkey.api.module.CodeOnlyModule;
2222
import org.labkey.api.module.ModuleContext;
2323
import org.labkey.api.security.AuthenticationManager;
24-
import org.labkey.api.settings.OptionalFeatureFlag;
2524
import org.labkey.api.settings.OptionalFeatureService;
2625
import org.labkey.api.util.JspTestCase;
2726
import org.labkey.api.view.WebPartFactory;
@@ -62,10 +61,10 @@ protected void init()
6261
addController("testsso", TestSsoController.class);
6362
AuthenticationManager.registerProvider(new TestSsoProvider());
6463

65-
OptionalFeatureService.get().addFeatureFlag(new OptionalFeatureFlag(Domain.EXPERIMENTAL_FUZZ_STORAGE_NAME,
64+
OptionalFeatureService.get().addExperimentalFeatureFlag(Domain.EXPERIMENTAL_FUZZ_STORAGE_NAME,
6665
"'fuzz' name of database columns used to back domain properties",
6766
"This is dev/test feature and not intended for any production usage.",
68-
false, false, OptionalFeatureService.FeatureType.Experimental));
67+
false, true);
6968
}
7069

7170
@Override

experiment/src/org/labkey/experiment/ExperimentModule.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ protected void init()
262262
ExperimentService.get().registerNameExpressionType("dataclass", "exp", "DataClass", "nameexpression");
263263

264264
OptionalFeatureService.get().addExperimentalFeatureFlag(AppProps.EXPERIMENTAL_RESOLVE_PROPERTY_URI_COLUMNS, "Resolve property URIs as columns on experiment tables",
265-
"If a column is not found on an experiment table, attempt to resolve the column name as a Property URI and add it as a property column", false);
265+
"If a column is not found on an experiment table, attempt to resolve the column name as a Property URI and add it as a property column", false, true);
266266
if (CoreSchema.getInstance().getSqlDialect().isSqlServer())
267267
{
268268
OptionalFeatureService.get().addExperimentalFeatureFlag(NameGenerator.EXPERIMENTAL_WITH_COUNTER, "Use strict incremental withCounter and rootSampleCount expression",
@@ -282,9 +282,9 @@ protected void init()
282282
OptionalFeatureService.get().addExperimentalFeatureFlag(AppProps.QUANTITY_COLUMN_SUFFIX_TESTING, "Quantity column suffix testing",
283283
"If a column name contains a \"__<unit>\" suffix, this feature allows for testing it as a Quantity display column", false);
284284
OptionalFeatureService.get().addExperimentalFeatureFlag(ExperimentService.EXPERIMENTAL_FEATURE_FROM_EXPANCESTORS, "SQL syntax: 'FROM EXPANCESTORS()'",
285-
"Support for querying lineage of experiment objects", false);
285+
"Support for querying lineage of experiment objects", false, true);
286286
OptionalFeatureService.get().addExperimentalFeatureFlag(SampleTypeUpdateServiceDI.EXPERIMENTAL_FEATURE_ALLOW_ROW_ID_SAMPLE_MERGE, "Allow RowId to be accepted when merging samples",
287-
"If the incoming data includes a RowId column we will allow the column but ignore it's values.", false);
287+
"If the incoming data includes a RowId column we will allow the column but ignore it's values.", false, true);
288288

289289
RoleManager.registerPermission(new DesignVocabularyPermission(), true);
290290
RoleManager.registerRole(new SampleTypeDesignerRole());

query/src/org/labkey/query/QueryModule.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ public QuerySchema createSchema(DefaultSchema schema, Module module)
237237
DataViewService.get().registerProvider(InheritedQueryDataViewProvider.TYPE, new InheritedQueryDataViewProvider());
238238

239239
OptionalFeatureService.get().addExperimentalFeatureFlag(QueryView.EXPERIMENTAL_GENERIC_DETAILS_URL, "Generic [details] link in grids/queries",
240-
"This feature will turn on generating a generic [details] URL link in most grids.", false);
240+
"This feature will turn on generating a generic [details] URL link in most grids.", false, true);
241241
OptionalFeatureService.get().addExperimentalFeatureFlag(QueryServiceImpl.EXPERIMENTAL_LAST_MODIFIED, "Include Last-Modified header on query metadata requests",
242242
"For schema, query, and view metadata requests include a Last-Modified header such that the browser can cache the response. " +
243243
"The metadata is invalidated when performing actions such as creating a new List or modifying the columns on a custom view", false);

0 commit comments

Comments
 (0)