Author: chabotc
Date: Tue Feb 9 08:29:28 2010
New Revision: 907966
URL: http://svn.apache.org/viewvc?rev=907966&view=rev
Log:
Fix external feature code generation to include dependencies (SHINDIG-1260) by
Jacky Wang
Modified:
shindig/trunk/php/src/gadgets/GadgetFactory.php
shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php
shindig/trunk/php/src/gadgets/render/GadgetBaseRenderer.php
shindig/trunk/php/src/gadgets/render/GadgetRenderer.php
shindig/trunk/php/src/gadgets/render/GadgetUrlRenderer.php
shindig/trunk/php/src/gadgets/servlet/JsServlet.php
Modified: shindig/trunk/php/src/gadgets/GadgetFactory.php
URL:
http://svn.apache.org/viewvc/shindig/trunk/php/src/gadgets/GadgetFactory.php?rev=907966&r1=907965&r2=907966&view=diff
==============================================================================
--- shindig/trunk/php/src/gadgets/GadgetFactory.php (original)
+++ shindig/trunk/php/src/gadgets/GadgetFactory.php Tue Feb 9 08:29:28 2010
@@ -72,7 +72,7 @@
$found = $missing = array();
if (! $this->context->getRegistry()->resolveFeatures(
array_merge($gadget->gadgetSpec->requiredFeatures,
$gadget->gadgetSpec->optionalFeatures),
- $found, $missing, true)) {
+ $found, $missing)) {
$requiredMissing = false;
foreach ($missing as $featureName) {
if (in_array($featureName, $gadget->gadgetSpec->requiredFeatures)) {
Modified: shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php
URL:
http://svn.apache.org/viewvc/shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php?rev=907966&r1=907965&r2=907966&view=diff
==============================================================================
--- shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php (original)
+++ shindig/trunk/php/src/gadgets/GadgetFeatureRegistry.php Tue Feb 9 08:29:28
2010
@@ -28,7 +28,8 @@
public $features;
private $coreDone = false;
private $coreFeaturs;
-
+ private $sortedFeatures;
+
public function __construct($featurePath) {
$this->registerFeatures($featurePath);
}
@@ -86,90 +87,41 @@
return $ret;
}
- public function resolveFeatures($needed, &$resultsFound, &$resultsMissing,
$isExpand) {
+ public function resolveFeatures($needed, &$resultsFound, &$resultsMissing) {
$resultsFound = array();
$resultsMissing = array();
if (! count($needed)) {
- // Shortcut for gadgets that don't have any explicit dependencies.
- $resultsFound = $this->coreFeatures;
- return true;
+ $needed = $this->coreFeatures;
}
foreach ($needed as $featureName) {
$feature = isset($this->features[$featureName]) ?
$this->features[$featureName] : null;
if ($feature == null) {
$resultsMissing[] = $featureName;
} else {
- $this->addFeatureToResults($resultsFound, $feature, $isExpand);
+ $this->addFeatureToResults($resultsFound, $feature);
}
}
return count($resultsMissing) == 0;
}
- public function sortFeatures($features, $forcedJsLibs,
&$sortedFeatureGroups) {
- $sortedFeatureGroups = array();
- if (empty($features)) return;
-
- // Topological sorting with constrain
- // Build the topology matrix
- $sortedFeatures = array();
- $reverseDeps = array();
- foreach ($features as $feature) {
- $reverseDeps[$feature] = array();
- }
- $depCount = array();
- foreach ($features as $feature) {
- $deps = $this->features[$feature]['deps'];
- $deps = array_uintersect($deps, $features, "strcasecmp");
- $depCount[$feature] = count($deps);
- foreach ($deps as $dep) {
- $reverseDeps[$dep][] = $feature;
- }
+ public function sortFeatures($features, &$sortedFeatures) {
+ if (empty($features)) {
+ return;
}
-
- // iterate to do the sorting
- $prevIsForcedJsLibs = true;
- $featureQueue = array();
- while (! empty($depCount)) {
- $fail = true;
- while (! empty($depCount)) { // get grouped features greedily
- $foundAll = true;
- foreach ($depCount as $feature => $count) {
- if ($count != 0) continue;
- $fail = false; // found at least one root node
- if ((! $prevIsForcedJsLibs) ^ in_array($feature, $forcedJsLibs)) {
- $foundAll = false;
- $featureQueue[] = $feature;
- foreach ($reverseDeps[$feature] as $reverseDep) {
- $depCount[$reverseDep] -= 1;
- }
- unset($depCount[$feature]);
- }
- }
- if ($foundAll) break;
- }
- if ($fail) {
- throw new GadgetException("Sorting feature dependence failed: it
contains ring!");
- }
- if (! empty($featureQueue)) {
- if ($prevIsForcedJsLibs) {
- $sortedFeatureGroups[] = array('type' => 'external', 'features' =>
$featureQueue);
- } else {
- $sortedFeatureGroups[] = array('type' => 'inline', 'features' =>
$featureQueue);
- }
+ $sortedFeatures = array();
+ foreach ($this->sortedFeatures as $feature) {
+ if (in_array($feature, $features)) {
+ $sortedFeatures[] = $feature;
}
- $prevIsForcedJsLibs = ! $prevIsForcedJsLibs;
- $featureQueue = array();
}
}
- private function addFeatureToResults(&$results, $feature, $isExpand) {
+ private function addFeatureToResults(&$results, $feature) {
if (in_array($feature['name'], $results)) {
return;
}
- if ($isExpand) {
- foreach ($feature['deps'] as $dep) {
- $this->addFeatureToResults($results, $this->features[$dep], true);
- }
+ foreach ($feature['deps'] as $dep) {
+ $this->addFeatureToResults($results, $this->features[$dep]);
}
if (!in_array($feature['name'], $results)) {
$results[] = $feature['name'];
@@ -214,6 +166,41 @@
$this->features[$key]['deps'] = array_merge($entry['deps'],
$this->coreFeatures);
}
}
+ // Topologically sort all features according to their dependency
+ $features = array();
+ foreach ($this->features as $feature) {
+ $features[] = $feature['name'];
+ }
+ $sortedFeatures = array();
+ $reverseDeps = array();
+ foreach ($features as $feature) {
+ $reverseDeps[$feature] = array();
+ }
+ $depCount = array();
+ foreach ($features as $feature) {
+ $deps = $this->features[$feature]['deps'];
+ $deps = array_uintersect($deps, $features, "strcasecmp");
+ $depCount[$feature] = count($deps);
+ foreach ($deps as $dep) {
+ $reverseDeps[$dep][] = $feature;
+ }
+ }
+ while (! empty($depCount)) {
+ $fail = true;
+ foreach ($depCount as $feature => $count) {
+ if ($count != 0) continue;
+ $fail = false;
+ $sortedFeatures[] = $feature;
+ foreach ($reverseDeps[$feature] as $reverseDep) {
+ $depCount[$reverseDep] -= 1;
+ }
+ unset($depCount[$feature]);
+ }
+ if ($fail && ! empty($depCount)) {
+ throw new GadgetException("Sorting feature dependence failed: it
contains ring!");
+ }
+ }
+ $this->sortedFeatures = $sortedFeatures;
}
/**
Modified: shindig/trunk/php/src/gadgets/render/GadgetBaseRenderer.php
URL:
http://svn.apache.org/viewvc/shindig/trunk/php/src/gadgets/render/GadgetBaseRenderer.php?rev=907966&r1=907965&r2=907966&view=diff
==============================================================================
--- shindig/trunk/php/src/gadgets/render/GadgetBaseRenderer.php (original)
+++ shindig/trunk/php/src/gadgets/render/GadgetBaseRenderer.php Tue Feb 9
08:29:28 2010
@@ -300,25 +300,36 @@
public function getJavaScripts() {
$registry = $this->context->getRegistry();
$forcedJsLibs = $this->getForcedJsLibs();
- $sortedFeatureGroups = array();
- $registry->sortFeatures($this->gadget->features, $forcedJsLibs,
$sortedFeatureGroups);
- $scripts = array();
-
- // if some of the feature libraries are externalized (through a browser
cachable <script src="/gadgets/js/opensocial-0.9:settitle.js"> type url)
- // we inject the tag and don't inline those libs (and their dependencies)
- foreach ($sortedFeatureGroups as $featureGroup) {
- if ($featureGroup['type'] == 'inline') {
- $featureGroup['content'] =
$registry->getFeaturesContent($featureGroup['features'], $this->context, true);
+ $externFeatures = array();
+ $inlineFeatures = array();
+ foreach ($this->gadget->features as $feature) {
+ if (in_array($feature, $forcedJsLibs)) {
+ $externFeatures[] = $feature;
} else {
- $featureGroup['content'] = Config::get('default_js_prefix') .
$this->getJsUrl($featureGroup['features']) . "&container=" .
$this->context->getContainer();
+ $inlineFeatures[] = $feature;
}
- $scripts[] = $featureGroup;
}
+ $sortedExternFeatures = array();
+ $sortedInlineFeatures = array();
+ $registry->sortFeatures($externFeatures, $sortedExternFeatures);
+ $registry->sortFeatures($inlineFeatures, $sortedInlineFeatures);
+ // if some of the feature libraries are externalized (through a browser
cachable <script src="/gadgets/js/opensocial-0.9:settitle.js"> type url)
+ // we inject the tag and don't inline those libs (and their dependencies)
+ $scripts = array();
+ if (! empty($sortedExternFeatures)) {
+ $scripts[] = array(
+ 'type' => 'extern',
+ 'content' => Config::get('default_js_prefix') .
$this->getJsUrl($sortedExternFeatures) . "&container=" .
$this->context->getContainer()
+ );
+ }
$script = '';
+ foreach ($sortedInlineFeatures as $feature) {
+ $script .= $registry->getFeatureContent($feature, $this->context, true);
+ }
// Add the JavaScript initialization strings for the configuration,
localization and preloads
$script .= "\n";
- $script .= $this->appendJsConfig($this->gadget, $sortedFeatureGroups);
+ $script .= $this->appendJsConfig($this->gadget, $sortedExternFeatures,
$sortedInlineFeatures);
$script .= $this->appendMessages($this->gadget);
$script .= $this->appendPreloads($this->gadget);
if (count($this->dataInserts)) {
@@ -380,7 +391,13 @@
if (empty($forcedJsLibs)) {
return array();
} else {
- return explode(':', $forcedJsLibs);
+ $features = explode(':', $forcedJsLibs);
+ // expend features here
+ $resultsFound = array();
+ $resultsMissing = array();
+ $registry = $this->context->getRegistry();
+ $registry->resolveFeatures($features, $resultsFound, $resultsMissing);
+ return $resultsFound;
}
}
@@ -388,23 +405,19 @@
* Appends the javascript features configuration string
*
* @param Gadget $gadget
- * @param $featureGroups
+ * @param $externFeatures
+ * @param $inlineFeatures
* @return string
*/
- private function appendJsConfig(Gadget $gadget, $featureGroups) {
+ private function appendJsConfig(Gadget $gadget, $externFeatures,
$inlineFeatures) {
$container = $this->context->getContainer();
$containerConfig = $this->context->getContainerConfig();
- $forcedJsLibs = $this->getForcedJsLibs();
$gadgetConfig = array();
$featureConfig = $containerConfig->getConfig($container,
'gadgets.features');
// TODO some day we should parse the forcedLibs too, and include their
config selectivly as well.
// For now we just include everything.
- $features = array();
- foreach ($featureGroups as $featureGroup) {
- $features = array_merge($features, $featureGroup['features']);
- }
-
+ $features = array_merge($externFeatures, $inlineFeatures);
foreach ($features as $feature) {
if (! isset($gadgetConfig[$feature]) && !
empty($featureConfig[$feature])) {
$gadgetConfig[$feature] = $featureConfig[$feature];
Modified: shindig/trunk/php/src/gadgets/render/GadgetRenderer.php
URL:
http://svn.apache.org/viewvc/shindig/trunk/php/src/gadgets/render/GadgetRenderer.php?rev=907966&r1=907965&r2=907966&view=diff
==============================================================================
--- shindig/trunk/php/src/gadgets/render/GadgetRenderer.php (original)
+++ shindig/trunk/php/src/gadgets/render/GadgetRenderer.php Tue Feb 9 08:29:28
2010
@@ -33,7 +33,7 @@
* generates the library string (core:caja:etc.js) including a checksum of
all the
* javascript content (?v=<md5 of js>) for cache busting
*
- * @param string $libs
+ * @param string $features
* @param Gadget $gadget
* @return string the list of libraries in core:caja:etc.js?v=checksum>
format
*/
Modified: shindig/trunk/php/src/gadgets/render/GadgetUrlRenderer.php
URL:
http://svn.apache.org/viewvc/shindig/trunk/php/src/gadgets/render/GadgetUrlRenderer.php?rev=907966&r1=907965&r2=907966&view=diff
==============================================================================
--- shindig/trunk/php/src/gadgets/render/GadgetUrlRenderer.php (original)
+++ shindig/trunk/php/src/gadgets/render/GadgetUrlRenderer.php Tue Feb 9
08:29:28 2010
@@ -40,17 +40,10 @@
$registry = $this->context->getRegistry();
// since the URL mode doesn't actually have the gadget XML body, it can't
inline
// the javascript content anyway - thus could us just ignore the
'forcedJsLibs' part.
- $forcedJsLibs = array();
- $sortedFeatureGroups = array();
- $registry->sortFeatures($gadget->features, $forcedJsLibs,
$sortedFeatureGroups);
+ $sortedFeatures = array();
+ $registry->sortFeatures($gadget->features, $sortedFeatures);
- // join the groups
- $features = array();
- foreach ($sortedFeatureGroups as $featureGroup) {
- $features = array_merge($features, $featureGroup['features']);
- }
-
- $query .= $this->appendLibsToQuery($features);
+ $query .= $this->appendLibsToQuery($sortedFeatures);
$query .= '&lang=' . urlencode(isset($_GET['lang']) ? $_GET['lang'] :
'en');
$query .= '&country=' . urlencode(isset($_GET['country']) ?
$_GET['country'] : 'US');
if (substr($query, 0, 1) == '&') {
Modified: shindig/trunk/php/src/gadgets/servlet/JsServlet.php
URL:
http://svn.apache.org/viewvc/shindig/trunk/php/src/gadgets/servlet/JsServlet.php?rev=907966&r1=907965&r2=907966&view=diff
==============================================================================
--- shindig/trunk/php/src/gadgets/servlet/JsServlet.php (original)
+++ shindig/trunk/php/src/gadgets/servlet/JsServlet.php Tue Feb 9 08:29:28 2010
@@ -56,7 +56,7 @@
$missing = array();
$context = new GadgetContext('GADGET');
$registry = new GadgetFeatureRegistry(Config::get('features_path'));
- if ($registry->resolveFeatures($needed, $found, $missing, false)) {
+ if ($registry->resolveFeatures($needed, $found, $missing)) {
$isGadgetContext = !isset($_GET["c"]) || $_GET['c'] == 0 ? true : false;
$jsData = '';
foreach ($found as $feature) {