Table StyleProvider throws SecurityException: No security context bound to the current thread

I got this exception when I try to refresh Table which is the super class of ExtChargeBrowse.
How can I refresh the table when it is inherited?


List<Charge> saveList = new ArrayList<>();

BackgroundTask<Integer, Void> task = new BackgroundTask<Integer, Void>(30, this) {
    @Override
    public Void run(TaskLifeCycle<Integer> taskLifeCycle) throws Exception {
        lotus.domino.Session notesSession = NotesFactory.createSession("", "", "");
        Database db = notesSession.getDatabase("", "");
        View view = db.getView("Smelting");
        ViewEntryCollection allEntries = view.getAllEntries();
        if(allEntries.getCount() > 0) {
            ViewEntry firstEntry = allEntries.getFirstEntry();
            while(firstEntry != null){
                Document document = firstEntry.getDocument();
                if(document.getItemValueString("Chargenr").length() > 0){
                    Charge charge = metadata.create(Charge.class);
                    charge.setChargeNo(document.getItemValueString("Chargenr"));
                    charge.setWorkOrder(Integer.valueOf(document.getItemValueString("Workorder")));
                    saveList.add(charge);
                }
                firstEntry = allEntries.getNextEntry(firstEntry);
            }
        }
        allEntries.recycle();
        view.recycle();
        db.recycle();

        saveCharges(saveList);

        return null;
    }

    @Override
    public void progress(List<Integer> changes) {
        super.progress(changes);
    }

    @Override
    public void done(Void result) {
        ExtChargeBrowse.this.chargesTable.refresh();
    }
};

BackgroundTaskHandler taskHandler = backgroundWorker.handle(task);
taskHandler.execute();

localhost.2016-10-17.log (112.8K)

Hi,

I think it is the bug in WebBackgroundWorker, we will fix it in the next bug fix version of the platform.

Thank you for reporting the problem.

After detailed investigation, I see that the problem is caused by service call from StyleProvider. Table StyleProvider is called on JSON serialization stage where SecurityContext is inaccessible.

You have to call services only from event handling logic, for example - from CollectionDatasource listener, because any exception on JSON serialization will lead to Internal Exception message on the browser side. Also, you should not call services from StyleProvider because it can lead to an unpredictable count of service calls, StyleProvider is called for each cell of a Table that is visible on the browser side. Any StyleProvider should work only with loaded data to be as fast as possible.

So, we do not plan to change this behaviour in the future, but we will add these details in JavaDoc and documentation.

To solve this problem I recommend to move your data loading code to CollectionDatasource listener and assign styles from StyleProvider based only on loaded data.

Do you have the ability to create a project which shows the correct way to deal with this.
It may help others to do it the correct way.

Hi,

in this case, I would use CollectionDatasource listener along with preloaded calculatable values.

Let’s say I have an entity - Order. I need to show a price of an order with some styling: red font color for CHEAP orders and orange font color for EXPENSIVE orders. I have some business method in a special service that can tell me if an order is CHEAP or is EXPENSIVE.

I will redesign my business method to be able to get price categories for all the passed orders.


public interface OrderPriceService {
    String NAME = "demo_OrderPriceService";

    Map<UUID, PriceCategory> getPriceCategories(Collection<Order> order);

    enum PriceCategory {
        CHEAP,
        EXPENSIVE
    }
}

Then I will obtain price categories for all the orders in my data source:


@Inject
private CollectionDatasource<Order, UUID> ordersDs;

@Inject
private OrderPriceService orderPriceService;

// Some calculatable values for all orders
private Map<UUID, PriceCategory> priceCategories = Collections.emptyMap();

@Override
public void init(Map<String, Object> params) {
    super.init(params);

    ordersDs.addCollectionChangeListener(e -> {
        // update price categories using service call
        priceCategories = orderPriceService.getPriceCategories(ordersDs.getItems());
    });

And finally I can return style name for my price without service call on each cell in my table:


ordersTable.setStyleProvider((order, property) -> {
    if ("price".equals(property)) {
        PriceCategory priceCategory = priceCategories.get(order.getId());
        if (priceCategory == null) {
            return null;
        }
        if (priceCategory == PriceCategory.CHEAP) {
            return "cheap";
        } else {
            return "expensive";
        }
    }

    return null;
});

I’ve uploaded the sample; you can see all the code there.

styles-service.zip (29.3K)