Skip to content

More on adjunct highlights#818

Merged
asfgit merged 6 commits intoapache:masterfrom
ahgittin:highlights-adjuncts
Sep 16, 2017
Merged

More on adjunct highlights#818
asfgit merged 6 commits intoapache:masterfrom
ahgittin:highlights-adjuncts

Conversation

@ahgittin
Copy link
Copy Markdown
Contributor

Applies #813 to a policy (ServiceRestarter) to see how it works. As reported there it works good, REST and persistence acting as expected.

The API for policy authors was a little awkward, and there were some PR review comments in #813. This addresses both of these.

I will be adding highlight info to more policies and adjuncts. If this is reviewed in time I'll do it in a different branch, else I'll add them here for simplicity.

@ahgittin
Copy link
Copy Markdown
Contributor Author

See 5ae9c41#diff-0724222c7ef44a5337e1e8f44d9d5faeR114 for illustration of what I mean by an easier adjunct java author API (just some convenience methods to allow DRY).

* selected policies (autoscaler, restarter, replacer, membership trackers)  - triggers, actions, and confirmations/violations
* triggers for most enrichers (with new conveniences added for sensor triggers)
* period trigger for all feeds (from `Poller` using new `highlightTriggerPeriod` in `AbstractFeed`)
* publish sensor actions for all enrichers (new `highlightActionPublishSensor` convenience for `AbstractEntityAdjuct`, called in `AbstractEnricher`, and in feed handlers via new `AbstractFeed.onSensor..` methods)
@ahgittin
Copy link
Copy Markdown
Contributor Author

Now has highlights on most things.

Copy link
Copy Markdown
Contributor

@Graeme-Miller Graeme-Miller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, only minor comments

protected <U> void highlightTriggers(Sensor<?> s, Iterable<U> sources) {
highlightTriggers(Collections.singleton(s), sources);
}
protected <T,U> void highlightTriggers(Iterable<? extends Sensor<? extends T>> sensors, Iterable<U> sources) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method would benefit from comments to explain what it is doing, with multiple loops and nested ifs it isn't easy to tell at a glance.


/** As {@link #setHighlight(String, HighlightTuple)}, convenience for recording an item which is intended to be ongoing. */
protected void highlightOngoing(String name, String description) {
highlights.put(name, new HighlightTuple(description, 0, null));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be calling setHighlight, rather than putting directly into the map. This would allow these methods to remain uncoupled from how we store the highlights. Same for the below highlight methods.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree

protected <T,U> void highlightTriggers(Iterable<? extends Sensor<? extends T>> sensors, Iterable<U> sources) {
StringBuilder msg = new StringBuilder("Listening for ");
boolean firstWord = true;
if (sensors!=null) for (Object s: sensors) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have a style guide for brooklyn? I have never seen someone put a for loop on the same line as an if. Seems to break with our coding conventions.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree for the sake of readability please add braces and a line break

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clearly bad style, no argument! i added the guard when debugging, forgot to format it nicely...

}
if (firstWord) msg.append("<nothing>");

firstWord = true;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lines 620 -> 639 are confusing and it is difficult to extract what the code is supposed to do. I had a go at what I think is a simpler solution:

        if(!myList.isEmpty() && !(myList.size() == 1 && myList.iterator().next().equals(getEntity())) {
            msg.append(" on ");
            List<String> stringList = myList.stream().map((Sensor s) -> {
                if (s.equals(getEntity())) {
                    return "self";
                } else if (s instanceof Sensor) {
                    return ((Sensor<?>) s).getName();
                } else {
                    return s.toString();
                }
            }).collect(Collectors.toList());
            msg.append(String.join(",", stringList));
        }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting @Graeme-Miller - Not sure that you need the second clause in your if, as the body handles the self output the same as the original code. I'd prefer the Collectors.joining(", ") collector, to get a String out directly... Also, I'm not sure you should try and chest the lambda type inference like that, just go s -> { /* stuff */ } and it'll be fine. Redoing the whole method with lambdas gave me this, which is almost exactly the same length ;)

    protected <T,U> void highlightTriggers(Iterable<? extends Sensor<? extends T>> sensors, Iterable<U> sources) {
        StringBuilder msg = new StringBuilder("Listening for ");
        if (Iterables.isEmpty(sensors)) {
            msg.append("<nothing>");
        } else {
            String sensorsText = StreamSupport.stream(sensors.spliterator(), false)
                    .filter(s -> s != null)
                    .map(s -> {
                        if (s instanceof Sensor) {
                            return ((Sensor<?>) s).getName();
                        } else {
                            return s.toString();
                        }
                    })
                    .collect(Collectors.joining(", "));
            msg.append(sensorsText);
        }
        if (!Iterables.isEmpty(sources)) {
            String sourcesText = StreamSupport.stream(sources.spliterator(), false)
                    .filter(s -> s != null)
                    .map(s -> {
                        if (s.equals(getEntity())) {
                            return "self";
                        } else if (s instanceof Sensor) {
                            return ((Sensor<?>) s).getName();
                        } else {
                            return s.toString();
                        }
                    })
                    .collect(Collectors.joining(", "));
            msg.append(" on ")
               .append(sourcesText);
        }
        highlightTriggers(msg.toString());
    }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@grkvlt very interesting, didn't know about Collectors.joining(", "), that's very handy.

re. the second clause in the if. My understanding of Alex's code is that, if there is only one entry, and that entry is self, then we shouldn't add "on...". The second clause in the if is to guard against that. Maybe Alex can clarify?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great suggestions -- so used to using lambas in JS but not in java :)

using choice operator to make more concise, going with:

        if (sensors==null || Iterables.isEmpty(sensors)) {
            msg.append("<nothing>");
        } else {
            String sensorsText = StreamSupport.stream(sensors.spliterator(), false)
                    .filter(s -> s != null)
                    .map(s -> (s instanceof Sensor ? ((Sensor<?>) s).getName() : s.toString()))
                    .collect(Collectors.joining(", "));
            msg.append(sensorsText);
        }

        if (sources!=null && !Iterables.isEmpty(sources)) {
            String sourcesText = StreamSupport.stream(sources.spliterator(), false)
                    .filter(s -> s != null)
                    .map(s -> (s.equals(getEntity()) ? "self" : s.toString()))
                    .collect(Collectors.joining(", "));
            if (!"self".equals(sourcesText)) {
                msg.append(" on ").append(sourcesText);
            }
        }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks nice @ahgittin - it's taken me a while to get used to operating in this style with Java as well, but it does makes things both concise and still readable...

@ahgittin
Copy link
Copy Markdown
Contributor Author

all addressed, thanks. if build passes then let's merge.

@ahgittin
Copy link
Copy Markdown
Contributor Author

fixed test failure as streaming with lambdas enforces generic information (did not know that - kinda cool actually)

@asfgit asfgit merged commit 13c368a into apache:master Sep 16, 2017
asfgit pushed a commit that referenced this pull request Sep 16, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants