/** * check the top level component/app and get dependencies. * * <p>This routine checks to see that we have a valid top level component. If our top level * component is out of sync, we have to ignore it here, but we _must_ force the client to not * cache the response. * * <p>If there is a QFE, we substitute the QFE descriptor for the one given us, and continue. * Again, we cannot allow caching. * * <p>Finally, if there is no descriptor given, we simply ignore the request and give them an * empty response. Which is done here by returning null. * * <p>Also note that this handles the 'if-modified-since' header, as we want to tell the browser * that nothing changed in that case. * * @param request the request (for exception handling) * @param response the response (for exception handling) * @param context the context to get the definition. * @return the set of descriptors we are sending back, or null in the case that we handled the * response. * @throws IOException if there was an IO exception handling a client out of sync exception * @throws ServletException if there was a problem handling the out of sync */ @Override public Set<DefDescriptor<?>> verifyTopLevel( HttpServletRequest request, HttpServletResponse response, AuraContext context) throws IOException { DefDescriptor<? extends BaseComponentDef> appDesc = context.getApplicationDescriptor(); MasterDefRegistry mdr = context.getDefRegistry(); context.setPreloading(true); if (appDesc == null) { // // This means we have nothing to say to the client, so the response is // left completely empty. // return null; } long ifModifiedSince = request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE); String uid = context.getUid(appDesc); try { try { definitionService.updateLoaded(appDesc); if (uid != null && ifModifiedSince != -1) { // // In this case, we have an unmodified descriptor, so just tell // the client that. // response.sendError(HttpServletResponse.SC_NOT_MODIFIED); return null; } } catch (ClientOutOfSyncException coose) { // // We can't actually handle an out of sync here, since we are doing a // resource load. We have to ignore it, and continue as if nothing happened. // But in the process, we make sure to set 'no-cache' so that the result // is thrown away. This may actually not give the right result in bizarre // corner cases... beware cache inconsistencies on revert after a QFE. // // We actually probably should do something different, like send a minimalist // set of stuff to make the client re-try. // this.setNoCache(response); String oosUid = mdr.getUid(null, appDesc); return mdr.getDependencies(oosUid); } } catch (QuickFixException qfe) { // // A quickfix exception means that we couldn't compile something. // In this case, we still want to preload things, but we want to preload // quick fix values, note that we force NoCache here. // this.setNoCache(response); this.handleServletException(qfe, true, context, request, response, true); return null; } this.setLongCache(response); if (uid == null) { uid = context.getUid(appDesc); } return mdr.getDependencies(uid); }
/** Start a context and set up default values. */ protected AuraContext setupContext( Mode mode, Format format, DefDescriptor<? extends BaseComponentDef> desc) throws QuickFixException { ContextService contextService = Aura.getContextService(); AuraContext ctxt = contextService.startContext(mode, format, Authentication.AUTHENTICATED, desc); ctxt.setFrameworkUID(Aura.getConfigAdapter().getAuraFrameworkNonce()); String uid = ctxt.getDefRegistry().getUid(null, desc); ctxt.addLoaded(desc, uid); return ctxt; }
@SuppressWarnings("unchecked") private List<DefDescriptor<FlavoredStyleDef>> getDefs() { AuraContext context = Aura.getContextService().getCurrentContext(); MasterDefRegistry mdr = context.getDefRegistry(); List<DefDescriptor<FlavoredStyleDef>> defs = new ArrayList<>(); for (DefDescriptor<?> dd : mdr.find(filter)) { // currently getBundle will only work with file-based, unless the other loaders also set the // bundle if (dd.getDefType() == DefType.FLAVORED_STYLE && dd.getBundle().getName().equals(bundle)) { defs.add((DefDescriptor<FlavoredStyleDef>) dd); } } return defs; }
private void loadTestMocks(AuraContext context, boolean doReset, Collection<Definition> mocks) { // TODO: fix error handling if (mocks == null || mocks.isEmpty()) { return; } boolean error = false; MasterDefRegistry registry = context.getDefRegistry(); for (Definition def : mocks) { try { if (doReset && def instanceof Resettable) { ((Resettable) def).reset(); } registry.addLocalDef(def); } catch (Throwable t) { LOG.error("Failed to add mock " + def, t); error = true; } } if (error) { Aura.get(TestContextAdapter.class).release(); } }
@Override public void serialize(Json json, AuraContext ctx) throws IOException { json.writeMapBegin(); json.writeMapEntry("mode", ctx.getMode()); DefDescriptor<? extends BaseComponentDef> appDesc = ctx.getApplicationDescriptor(); if (appDesc != null) { if (appDesc.getDefType().equals(DefType.APPLICATION)) { json.writeMapEntry( "app", String.format("%s:%s", appDesc.getNamespace(), appDesc.getName())); } else { json.writeMapEntry( "cmp", String.format("%s:%s", appDesc.getNamespace(), appDesc.getName())); } } if (ctx.getSerializeThemes()) { ThemeList themes = ctx.getThemeList(); if (!themes.isEmpty()) { List<String> stringed = Lists.newArrayList(); for (DefDescriptor<ThemeDef> theme : themes) { stringed.add(theme.getQualifiedName()); } json.writeMapEntry("themes", stringed); } Optional<String> dynamicVarsUid = themes.getActiveDynamicVarsUid(); if (dynamicVarsUid.isPresent()) { json.writeMapEntry("dynamicVarsUid", dynamicVarsUid.get()); } } if (ctx.getRequestedLocales() != null) { List<String> locales = new ArrayList<>(); for (Locale locale : ctx.getRequestedLocales()) { locales.add(locale.toString()); } json.writeMapEntry("requestedLocales", locales); } Map<String, String> loadedStrings = Maps.newHashMap(); Map<DefDescriptor<?>, String> clientLoaded = Maps.newHashMap(); clientLoaded.putAll(ctx.getClientLoaded()); for (Map.Entry<DefDescriptor<?>, String> entry : ctx.getLoaded().entrySet()) { loadedStrings.put( String.format( "%s@%s", entry.getKey().getDefType().toString(), entry.getKey().getQualifiedName()), entry.getValue()); clientLoaded.remove(entry.getKey()); } if (forClient) { for (DefDescriptor<?> deleted : clientLoaded.keySet()) { loadedStrings.put( String.format("%s@%s", deleted.getDefType().toString(), deleted.getQualifiedName()), DELETED); } } if (loadedStrings.size() > 0) { json.writeMapKey("loaded"); json.writeMap(loadedStrings); } if (ctx.getSerializeLastMod()) { json.writeMapEntry("lastmod", Long.toString(AuraBaseServlet.getLastMod())); } TestContextAdapter testContextAdapter = Aura.get(TestContextAdapter.class); if (testContextAdapter != null) { TestContext testContext = testContextAdapter.getTestContext(); if (testContext != null) { json.writeMapEntry("test", testContext.getName()); } } if (ctx.getFrameworkUID() != null) { json.writeMapEntry("fwuid", ctx.getFrameworkUID()); } if (forClient) { // client needs value providers, urls don't boolean started = false; for (GlobalValueProvider valueProvider : ctx.getGlobalProviders().values()) { if (!valueProvider.isEmpty()) { if (!started) { json.writeMapKey("globalValueProviders"); json.writeArrayBegin(); started = true; } json.writeComma(); json.writeIndent(); json.writeMapBegin(); json.writeMapEntry("type", valueProvider.getValueProviderKey().getPrefix()); json.writeMapEntry("values", valueProvider.getData()); json.writeMapEnd(); } } if (started) { json.writeArrayEnd(); } // // Now comes the tricky part, we have to serialize all of the definitions that are // required on the client side, and, of all types. This way, we won't have to handle // ugly cases of actual definitions nested inside our configs, and, we ensure that // all dependencies actually get sent to the client. Note that the 'loaded' set needs // to be updated as well, but that needs to happen prior to this. // Map<DefDescriptor<? extends Definition>, Definition> defMap; defMap = ctx.getDefRegistry().filterRegistry(ctx.getPreloadedDefinitions()); if (defMap.size() > 0) { List<Definition> componentDefs = Lists.newArrayList(); List<Definition> eventDefs = Lists.newArrayList(); List<Definition> libraryDefs = Lists.newArrayList(); for (Map.Entry<DefDescriptor<? extends Definition>, Definition> entry : defMap.entrySet()) { DefDescriptor<? extends Definition> desc = entry.getKey(); DefType dt = desc.getDefType(); Definition d = entry.getValue(); // // Ignore defs that ended up not being valid. This is arguably something // that the MDR should have done when filtering. // if (d != null) { if (DefType.COMPONENT.equals(dt) || DefType.APPLICATION.equals(dt)) { componentDefs.add(d); } else if (DefType.EVENT.equals(dt)) { eventDefs.add(d); } else if (DefType.LIBRARY.equals(dt)) { libraryDefs.add(d); } } } writeDefs(json, "componentDefs", componentDefs); writeDefs(json, "eventDefs", eventDefs); writeDefs(json, "libraryDefs", libraryDefs); } ctx.serializeAsPart(json); } json.writeMapEnd(); }