JCL Migration Analyzer Analyzes legacy JCL scripts for migration to modern batch processing and workflow orchestration systems like Spring Batch, Apache Airflow, Kubernetes Jobs, or shell scripts. Overview This skill provides comprehensive analysis and migration planning for JCL (Job Control Language) batch processing systems. It extracts job structures, converts JCL constructs to modern workflow patterns, maps data dependencies, and generates implementation-ready migration strategies. Key Migration Focus : JCL to modern orchestration with proper handling of COND logic inversion, data depende…

, line.strip()):\n count += 1\n return count\n \n def _count_pattern(self, pattern: str) -> int:\n \"\"\"Count occurrences of a regex pattern.\"\"\"\n count = 0\n for line in self.lines:\n if re.search(pattern, line, re.IGNORECASE):\n count += 1\n return count\n \n def _calculate_score(self, metrics: Dict[str, int]) -> int:\n \"\"\"Calculate overall complexity score.\"\"\"\n score = 0\n \n # Base score from lines of code\n score += metrics['total_lines'] / self.WEIGHTS['loc_per_point']\n \n # Add weighted factors\n score += metrics['paragraphs'] * self.WEIGHTS['paragraph_weight']\n score += metrics['calls'] * self.WEIGHTS['call_weight']\n score += metrics['files'] * self.WEIGHTS['file_weight']\n score += metrics['sql_statements'] * self.WEIGHTS['sql_weight']\n score += metrics['goto_statements'] * self.WEIGHTS['goto_weight']\n score += metrics['alter_statements'] * self.WEIGHTS['alter_weight']\n score += metrics['perform_varying'] * self.WEIGHTS['perform_varying_weight']\n \n return int(score)\n \n def _get_complexity_level(self, score: int) -> str:\n \"\"\"Categorize complexity level.\"\"\"\n if score \u003c 20:\n return 'Simple'\n elif score \u003c 50:\n return 'Moderate'\n elif score \u003c 100:\n return 'Complex'\n else:\n return 'Very Complex'\n \n def _estimate_effort(self, score: int) -> float:\n \"\"\"Estimate effort in person-days.\"\"\"\n # Rough estimate: 1 point = 0.5 days\n # This should be calibrated based on team experience\n base_days = score * 0.5\n \n # Add overhead for testing and documentation (30%)\n return round(base_days * 1.3, 1)\n \n def _identify_risks(self, metrics: Dict[str, int]) -> list:\n \"\"\"Identify risk factors.\"\"\"\n risks = []\n \n if metrics['goto_statements'] > 0:\n risks.append({\n 'type': 'control_flow',\n 'description': f\"Contains {metrics['goto_statements']} GO TO statements - requires refactoring\",\n 'severity': 'high'\n })\n \n if metrics['alter_statements'] > 0:\n risks.append({\n 'type': 'control_flow',\n 'description': f\"Contains {metrics['alter_statements']} ALTER statements - complex refactoring needed\",\n 'severity': 'critical'\n })\n \n if metrics['sql_statements'] > 10:\n risks.append({\n 'type': 'database',\n 'description': f\"High number of SQL operations ({metrics['sql_statements']}) - requires careful transaction design\",\n 'severity': 'medium'\n })\n \n if metrics['calls'] > 5:\n risks.append({\n 'type': 'dependencies',\n 'description': f\"Calls {metrics['calls']} external programs - coordinate migration with dependencies\",\n 'severity': 'medium'\n })\n \n if metrics['total_lines'] > 1000:\n risks.append({\n 'type': 'size',\n 'description': f\"Large program ({metrics['total_lines']} lines) - consider splitting into multiple services\",\n 'severity': 'medium'\n })\n \n if metrics['files'] > 5:\n risks.append({\n 'type': 'io',\n 'description': f\"Accesses {metrics['files']} files - design appropriate data access layer\",\n 'severity': 'low'\n })\n \n return risks\n\n\ndef main():\n parser = argparse.ArgumentParser(description='Estimate COBOL program migration complexity')\n parser.add_argument('cobol_file', type=Path, help='Path to COBOL source file')\n parser.add_argument('--detailed', action='store_true', help='Show detailed metrics')\n parser.add_argument('--json', action='store_true', help='Output as JSON')\n \n args = parser.parse_args()\n \n if not args.cobol_file.exists():\n print(f\"Error: File not found: {args.cobol_file}\")\n return 1\n \n estimator = ComplexityEstimator(args.cobol_file)\n result = estimator.estimate()\n \n if args.json:\n print(json.dumps(result, indent=2))\n else:\n print(f\"\\nComplexity Analysis: {result['program']}\")\n print(\"=\" * 60)\n print(f\"Complexity Level: {result['complexity_level']}\")\n print(f\"Complexity Score: {result['complexity_score']}\")\n print(f\"Estimated Effort: {result['estimated_effort_days']} person-days\")\n \n if args.detailed:\n print(\"\\nDetailed Metrics:\")\n print(\"-\" * 60)\n for key, value in result['metrics'].items():\n print(f\" {key.replace('_', ' ').title()}: {value}\")\n \n if result['risk_factors']:\n print(\"\\nRisk Factors:\")\n print(\"-\" * 60)\n for risk in result['risk_factors']:\n severity_marker = {\n 'critical': '🔴',\n 'high': '🟠',\n 'medium': '🟡',\n 'low': '🟢'\n }.get(risk['severity'], '⚪')\n print(f\" {severity_marker} [{risk['severity'].upper()}] {risk['description']}\")\n else:\n print(\"\\n✅ No significant risk factors identified\")\n \n print()\n \n return 0\n\n\nif __name__ == '__main__':\n exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":8386,"content_sha256":"047a5fe4e7134b58d6f5ef1b29a7105d509b1a64ac93ebf06e89a1488505a976"},{"filename":"scripts/extract-structure.py","content":"#!/usr/bin/env python3\n\"\"\"\nExtract structure from JCL (Job Control Language) files.\n\nThis script analyzes JCL source code and extracts:\n- Job structure (JOB, EXEC, DD statements)\n- Program execution steps\n- Dataset definitions\n- Conditional logic (COND)\n- Job dependencies\n- Workflow structure\n\"\"\"\n\nimport argparse\nimport json\nimport re\nfrom pathlib import Path\nfrom typing import Dict, List, Any\n\n\nclass LegacyStructureExtractor:\n \"\"\"Extract structural information from legacy source programs.\"\"\"\n \n def __init__(self, source_file: Path):\n self.source_file = source_file\n self.content = source_file.read_text(encoding='utf-8', errors='ignore')\n self.lines = self.content.split('\\n')\n \n def extract(self) -> Dict[str, Any]:\n \"\"\"Extract all structural information.\"\"\"\n return {\n 'program_name': self.extract_program_name(),\n 'divisions': self.extract_divisions(),\n 'working_storage': self.extract_working_storage(),\n 'file_definitions': self.extract_file_definitions(),\n 'paragraphs': self.extract_paragraphs(),\n 'calls': self.extract_calls(),\n 'copybooks': self.extract_copybooks(),\n 'sql_operations': self.extract_sql_operations(),\n 'statistics': self.calculate_statistics()\n }\n \n def extract_program_name(self) -> str:\n \"\"\"Extract program name from PROGRAM-ID.\"\"\"\n for line in self.lines:\n match = re.search(r'PROGRAM-ID\\.\\s+(\\S+)', line, re.IGNORECASE)\n if match:\n return match.group(1).rstrip('.')\n return self.source_file.stem\n \n def extract_divisions(self) -> Dict[str, int]:\n \"\"\"Find line numbers where divisions start.\"\"\"\n divisions = {}\n for i, line in enumerate(self.lines):\n for div_name in ['IDENTIFICATION', 'ENVIRONMENT', 'DATA', 'PROCEDURE']:\n if re.search(rf'{div_name}\\s+DIVISION', line, re.IGNORECASE):\n divisions[div_name] = i + 1\n return divisions\n \n def extract_working_storage(self) -> List[Dict[str, Any]]:\n \"\"\"Extract Working-Storage variables.\"\"\"\n variables = []\n in_working_storage = False\n \n for line in self.lines:\n if re.search(r'WORKING-STORAGE\\s+SECTION', line, re.IGNORECASE):\n in_working_storage = True\n continue\n if re.search(r'(PROCEDURE\\s+DIVISION|LINKAGE\\s+SECTION)', line, re.IGNORECASE):\n in_working_storage = False\n \n if in_working_storage:\n match = re.match(r'\\s*(\\d{2})\\s+(\\S+)\\s+(.+)', line)\n if match:\n level, name, rest = match.groups()\n pic_match = re.search(r'PIC\\s+(\\S+)', rest, re.IGNORECASE)\n variables.append({\n 'level': int(level),\n 'name': name,\n 'picture': pic_match.group(1) if pic_match else None,\n 'line': self.lines.index(line) + 1\n })\n \n return variables\n \n def extract_file_definitions(self) -> List[Dict[str, str]]:\n \"\"\"Extract file definitions from SELECT statements.\"\"\"\n files = []\n for line in self.lines:\n match = re.search(r'SELECT\\s+(\\S+)\\s+ASSIGN', line, re.IGNORECASE)\n if match:\n files.append({\n 'name': match.group(1),\n 'line': self.lines.index(line) + 1\n })\n return files\n \n def extract_paragraphs(self) -> List[Dict[str, Any]]:\n \"\"\"Extract paragraph and section names.\"\"\"\n paragraphs = []\n for i, line in enumerate(self.lines):\n # Match paragraph names (word followed by period at start of line)\n match = re.match(r'^([A-Z0-9\\-]+)\\.\\s*

JCL Migration Analyzer Analyzes legacy JCL scripts for migration to modern batch processing and workflow orchestration systems like Spring Batch, Apache Airflow, Kubernetes Jobs, or shell scripts. Overview This skill provides comprehensive analysis and migration planning for JCL (Job Control Language) batch processing systems. It extracts job structures, converts JCL constructs to modern workflow patterns, maps data dependencies, and generates implementation-ready migration strategies. Key Migration Focus : JCL to modern orchestration with proper handling of COND logic inversion, data depende…

, line.strip())\n if match and i > 0:\n para_name = match.group(1)\n # Skip division names\n if para_name not in ['IDENTIFICATION', 'ENVIRONMENT', 'DATA', 'PROCEDURE']:\n paragraphs.append({\n 'name': para_name,\n 'line': i + 1,\n 'type': 'section' if 'SECTION' in para_name else 'paragraph'\n })\n return paragraphs\n \n def extract_calls(self) -> List[Dict[str, Any]]:\n \"\"\"Extract CALL statements to other programs.\"\"\"\n calls = []\n for i, line in enumerate(self.lines):\n match = re.search(r'CALL\\s+[\\'\"](\\S+)[\\'\"]', line, re.IGNORECASE)\n if match:\n calls.append({\n 'program': match.group(1),\n 'line': i + 1\n })\n return calls\n \n def extract_copybooks(self) -> List[Dict[str, Any]]:\n \"\"\"Extract COPY statements.\"\"\"\n copybooks = []\n for i, line in enumerate(self.lines):\n match = re.search(r'COPY\\s+(\\S+)', line, re.IGNORECASE)\n if match:\n copybooks.append({\n 'name': match.group(1).rstrip('.'),\n 'line': i + 1\n })\n return copybooks\n \n def extract_sql_operations(self) -> List[Dict[str, Any]]:\n \"\"\"Extract embedded SQL operations.\"\"\"\n sql_ops = []\n in_sql = False\n sql_text = []\n sql_start = 0\n \n for i, line in enumerate(self.lines):\n if 'EXEC SQL' in line.upper():\n in_sql = True\n sql_start = i + 1\n sql_text = []\n \n if in_sql:\n sql_text.append(line.strip())\n \n if 'END-EXEC' in line.upper() and in_sql:\n in_sql = False\n sql_ops.append({\n 'statement': ' '.join(sql_text),\n 'line': sql_start\n })\n \n return sql_ops\n \n def calculate_statistics(self) -> Dict[str, int]:\n \"\"\"Calculate basic statistics.\"\"\"\n return {\n 'total_lines': len(self.lines),\n 'working_storage_vars': len(self.extract_working_storage()),\n 'paragraphs': len(self.extract_paragraphs()),\n 'calls': len(self.extract_calls()),\n 'copybooks': len(self.extract_copybooks()),\n 'sql_operations': len(self.extract_sql_operations())\n }\n\n\ndef main():\n parser = argparse.ArgumentParser(description='Extract structure from legacy source files')\n parser.add_argument('source_file', type=Path, help='Path to source file')\n parser.add_argument('--output', '-o', type=Path, help='Output JSON file (default: stdout)')\n \n args = parser.parse_args()\n \n if not args.source_file.exists():\n print(f\"Error: File not found: {args.source_file}\")\n return 1\n \n extractor = LegacyStructureExtractor(args.source_file)\n structure = extractor.extract()\n \n output_json = json.dumps(structure, indent=2)\n \n if args.output:\n args.output.write_text(output_json)\n print(f\"Structure written to {args.output}\")\n else:\n print(output_json)\n \n return 0\n\n\nif __name__ == '__main__':\n exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":7312,"content_sha256":"6b825c5771778da3c92e375cdbb74d8166c0d69cd5bdf9eaa5e157ccd7646f4f"},{"filename":"scripts/generate-java-classes.py","content":"#!/usr/bin/env python3\n\"\"\"\nGenerate Java POJO classes from legacy data structures.\n\nThis script parses legacy data structure definitions and generates corresponding\nJava classes with appropriate data types, getters, setters, and validation.\n\"\"\"\n\nimport argparse\nimport re\nfrom pathlib import Path\nfrom typing import List, Dict, Optional, Tuple\n\n\nclass FieldDefinition:\n \"\"\"Represents a COBOL field definition.\"\"\"\n \n def __init__(self, level: int, name: str, picture: Optional[str], occurs: Optional[int] = None):\n self.level = level\n self.name = name\n self.picture = picture\n self.occurs = occurs\n self.children: List[FieldDefinition] = []\n \n def is_group(self) -> bool:\n \"\"\"Check if this is a group item (no picture clause).\"\"\"\n return self.picture is None\n \n def to_java_type(self) -> str:\n \"\"\"Convert COBOL picture to Java type.\"\"\"\n if self.picture is None:\n # Group item - will be a nested class\n return self.to_java_class_name()\n \n pic = self.picture.upper()\n \n # Numeric types\n if re.match(r'^S?9+V?9*

JCL Migration Analyzer Analyzes legacy JCL scripts for migration to modern batch processing and workflow orchestration systems like Spring Batch, Apache Airflow, Kubernetes Jobs, or shell scripts. Overview This skill provides comprehensive analysis and migration planning for JCL (Job Control Language) batch processing systems. It extracts job structures, converts JCL constructs to modern workflow patterns, maps data dependencies, and generates implementation-ready migration strategies. Key Migration Focus : JCL to modern orchestration with proper handling of COND logic inversion, data depende…

, pic.replace('(', '').replace(')', '')):\n if 'V' in pic or 'COMP-3' in pic:\n return 'BigDecimal'\n digit_count = pic.count('9')\n if digit_count \u003c= 9:\n return 'int' if pic.startswith('S') or pic.startswith('9') else 'long'\n elif digit_count \u003c= 18:\n return 'long'\n else:\n return 'BigInteger'\n \n # Alphanumeric\n if pic.startswith('X'):\n return 'String'\n \n # Default to String for unknown patterns\n return 'String'\n \n def to_java_field_name(self) -> str:\n \"\"\"Convert COBOL name to Java field name (camelCase).\"\"\"\n parts = self.name.lower().replace('_', '-').split('-')\n return parts[0] + ''.join(p.capitalize() for p in parts[1:])\n \n def to_java_class_name(self) -> str:\n \"\"\"Convert COBOL name to Java class name (PascalCase).\"\"\"\n parts = self.name.lower().replace('_', '-').split('-')\n return ''.join(p.capitalize() for p in parts)\n\n\nclass CopybookParser:\n \"\"\"Parse COBOL copybook and extract field definitions.\"\"\"\n \n def __init__(self, copybook_file: Path):\n self.copybook_file = copybook_file\n self.content = copybook_file.read_text(encoding='utf-8', errors='ignore')\n self.lines = self.content.split('\\n')\n \n def parse(self) -> FieldDefinition:\n \"\"\"Parse copybook and return root field definition.\"\"\"\n fields = []\n \n for line in self.lines:\n # Match COBOL field definition: level number, name, and optional picture\n match = re.match(r'\\s*(\\d{2})\\s+(\\S+)(?:\\s+PIC\\s+(\\S+))?(?:\\s+OCCURS\\s+(\\d+))?', line, re.IGNORECASE)\n if match:\n level = int(match.group(1))\n name = match.group(2).rstrip('.')\n picture = match.group(3)\n occurs = int(match.group(4)) if match.group(4) else None\n \n field = FieldDefinition(level, name, picture, occurs)\n fields.append(field)\n \n # Build hierarchy\n return self._build_hierarchy(fields)\n \n def _build_hierarchy(self, fields: List[FieldDefinition]) -> FieldDefinition:\n \"\"\"Build hierarchical structure from flat field list.\"\"\"\n if not fields:\n return FieldDefinition(1, 'Root', None)\n \n root = fields[0]\n stack = [root]\n \n for field in fields[1:]:\n # Pop stack until we find the parent level\n while stack and stack[-1].level >= field.level:\n stack.pop()\n \n if stack:\n stack[-1].children.append(field)\n \n stack.append(field)\n \n return root\n\n\nclass JavaClassGenerator:\n \"\"\"Generate Java class from COBOL copybook structure.\"\"\"\n \n def __init__(self, root_field: FieldDefinition, package_name: str = 'com.example.model'):\n self.root = root_field\n self.package_name = package_name\n self.imports = set()\n \n def generate(self) -> str:\n \"\"\"Generate complete Java class.\"\"\"\n self._collect_imports(self.root)\n \n lines = []\n lines.append(f'package {self.package_name};')\n lines.append('')\n \n # Add imports\n if self.imports:\n for imp in sorted(self.imports):\n lines.append(f'import {imp};')\n lines.append('')\n \n # Generate class\n lines.append('/**')\n lines.append(f' * Generated from COBOL copybook: {self.root.name}')\n lines.append(' * Auto-generated - do not modify directly')\n lines.append(' */')\n lines.extend(self._generate_class(self.root, 0))\n \n return '\\n'.join(lines)\n \n def _collect_imports(self, field: FieldDefinition):\n \"\"\"Collect required imports.\"\"\"\n java_type = field.to_java_type()\n \n if java_type == 'BigDecimal':\n self.imports.add('java.math.BigDecimal')\n elif java_type == 'BigInteger':\n self.imports.add('java.math.BigInteger')\n elif field.occurs:\n self.imports.add('java.util.List')\n self.imports.add('java.util.ArrayList')\n \n for child in field.children:\n self._collect_imports(child)\n \n def _generate_class(self, field: FieldDefinition, indent_level: int) -> List[str]:\n \"\"\"Generate class definition recursively.\"\"\"\n lines = []\n indent = ' ' * indent_level\n \n class_name = field.to_java_class_name()\n \n lines.append(f'{indent}public class {class_name} {{')\n \n # Generate fields\n for child in field.children:\n field_indent = ' ' * (indent_level + 1)\n java_type = child.to_java_type()\n field_name = child.to_java_field_name()\n \n if child.occurs:\n lines.append(f'{field_indent}private List\u003c{java_type}> {field_name} = new ArrayList\u003c>();')\n else:\n lines.append(f'{field_indent}private {java_type} {field_name};')\n \n if field.children:\n lines.append('')\n \n # Generate getters and setters\n for child in field.children:\n field_indent = ' ' * (indent_level + 1)\n java_type = child.to_java_type()\n field_name = child.to_java_field_name()\n method_suffix = field_name[0].upper() + field_name[1:]\n \n if child.occurs:\n return_type = f'List\u003c{java_type}>'\n lines.append(f'{field_indent}public {return_type} get{method_suffix}() {{')\n lines.append(f'{field_indent} return {field_name};')\n lines.append(f'{field_indent}}}')\n lines.append('')\n lines.append(f'{field_indent}public void set{method_suffix}({return_type} {field_name}) {{')\n lines.append(f'{field_indent} this.{field_name} = {field_name};')\n lines.append(f'{field_indent}}}')\n else:\n lines.append(f'{field_indent}public {java_type} get{method_suffix}() {{')\n lines.append(f'{field_indent} return {field_name};')\n lines.append(f'{field_indent}}}')\n lines.append('')\n lines.append(f'{field_indent}public void set{method_suffix}({java_type} {field_name}) {{')\n lines.append(f'{field_indent} this.{field_name} = {field_name};')\n lines.append(f'{field_indent}}}')\n lines.append('')\n \n # Generate nested classes for group items\n for child in field.children:\n if child.is_group() and child.children:\n lines.extend(self._generate_class(child, indent_level + 1))\n lines.append('')\n \n lines.append(f'{indent}}}')\n \n return lines\n\n\ndef main():\n parser = argparse.ArgumentParser(description='Generate Java classes from legacy data structures')\n parser.add_argument('copybook', type=Path, help='Path to data structure definition file')\n parser.add_argument('--package', '-p', default='com.example.model', help='Java package name')\n parser.add_argument('--output-dir', '-o', type=Path, help='Output directory for Java files')\n \n args = parser.parse_args()\n \n if not args.copybook.exists():\n print(f\"Error: Data structure file not found: {args.copybook}\")\n return 1\n \n # Parse copybook\n parser_obj = CopybookParser(args.copybook)\n root_field = parser_obj.parse()\n \n # Generate Java class\n generator = JavaClassGenerator(root_field, args.package)\n java_code = generator.generate()\n \n # Write output\n if args.output_dir:\n args.output_dir.mkdir(parents=True, exist_ok=True)\n # Convert package name to path (e.g., com.example.model -> com/example/model)\n package_parts = args.package.split('.')\n package_path = args.output_dir.joinpath(*package_parts)\n package_path.mkdir(parents=True, exist_ok=True)\n \n output_file = package_path / f'{root_field.to_java_class_name()}.java'\n output_file.write_text(java_code)\n print(f\"Generated: {output_file}\")\n else:\n print(java_code)\n \n return 0\n\n\nif __name__ == '__main__':\n exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":9581,"content_sha256":"33060a573a7400df5785ceb0d44cb1907f3a295ce9afd9e5843987ae1de92f66"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"JCL Migration Analyzer","type":"text"}]},{"type":"paragraph","content":[{"text":"Analyzes legacy JCL scripts for migration to modern batch processing and workflow orchestration systems like Spring Batch, Apache Airflow, Kubernetes Jobs, or shell scripts.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Overview","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill provides comprehensive analysis and migration planning for JCL (Job Control Language) batch processing systems. It extracts job structures, converts JCL constructs to modern workflow patterns, maps data dependencies, and generates implementation-ready migration strategies.","type":"text"}]},{"type":"paragraph","content":[{"text":"Key Migration Focus","type":"text","marks":[{"type":"strong"}]},{"text":": JCL to modern orchestration with proper handling of COND logic inversion, data dependencies (DD statements), GDG generations, procedures (PROCs), and batch workflow patterns.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Use This Skill","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this skill when:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Analyzing JCL job files (.jcl, .JCL) for modernization","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Planning migration from mainframe batch processing to modern workflow systems","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Converting JCL job steps to Spring Batch, Apache Airflow, or shell scripts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Understanding JCL COND logic and conditional execution patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mapping JCL data sets (DD statements) to modern file operations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Extracting JCL procedures (PROCs) and symbolic parameters","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generating workflow definitions for orchestration platforms","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Estimating complexity and effort for JCL migration projects","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating migration documentation and strategy reports","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Modernizing mainframe batch jobs to cloud-native workflows","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User mentions: JCL analysis, mainframe job migration, batch workflow conversion, COND logic, job steps, procedures, workflow orchestration","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core Capabilities","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Job Analysis","type":"text"}]},{"type":"paragraph","content":[{"text":"Extract job structure (JOB card), step sequences, program invocations (EXEC PGM/PROC), conditional logic (COND, IF/THEN/ELSE), return codes, data sets (DD statements), resource requirements, and symbolic parameters.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Data Dependency Mapping","type":"text"}]},{"type":"paragraph","content":[{"text":"Extract input/output datasets, temporary datasets, GDG handling, concatenation, DISP parameters, and data flow between steps.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Procedure Analysis","type":"text"}]},{"type":"paragraph","content":[{"text":"Parse PROC definitions, symbolic parameters, PROC overrides, nested procedures, INCLUDE statements, and JCLLIB references.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. Workflow Migration","type":"text"}]},{"type":"paragraph","content":[{"text":"Generate Spring Batch jobs, Apache Airflow DAGs, Kubernetes Jobs, shell scripts, AWS Step Functions, or Azure Logic Apps.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"5. Conditional Logic Translation","type":"text"}]},{"type":"paragraph","content":[{"text":"CRITICAL","type":"text","marks":[{"type":"strong"}]},{"text":": COND logic is INVERTED! Map COND parameters, IF/THEN/ELSE, return codes, step bypassing, and restart logic to modern constructs.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1: Discover JCL Assets","type":"text"}]},{"type":"paragraph","content":[{"text":"Find JCL jobs and procedures in the workspace:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"find . -name \"*.jcl\" -o -name \"*.JCL\"\nfind . -name \"*.proc\" -o -name \"*.PROC\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"scripts/analyze-dependencies.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"scripts/analyze-dependencies.ps1","type":"text","marks":[{"type":"code_inline"}]},{"text":" to generate dependency graph in JSON format.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 2: Extract Structure","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"scripts/extract-structure.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" to parse JCL files and extract:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Job cards and parameters","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Step sequences and execution order","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Program/procedure invocations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"DD statements with DISP parameters","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"COND and IF/THEN/ELSE logic","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Symbolic parameters","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Output format: JSON with job structure, steps, and dependencies.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 3: Analyze Conditional Logic","type":"text"}]},{"type":"paragraph","content":[{"text":"CRITICAL","type":"text","marks":[{"type":"strong"}]},{"text":": Identify and document COND logic (which is INVERTED):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"COND=(0,NE)","type":"text","marks":[{"type":"code_inline"}]},{"text":" → Run if previous RC ≠ 0 (run on ERROR)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"COND=(0,EQ)","type":"text","marks":[{"type":"code_inline"}]},{"text":" → Skip if previous RC = 0 (skip on SUCCESS)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"IF/THEN/ELSE uses normal logic (not inverted)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Create truth tables for complex conditional logic to avoid errors in migration.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 4: Map Data Dependencies","type":"text"}]},{"type":"paragraph","content":[{"text":"Track data flow between steps:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Input datasets (DISP=SHR or OLD)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Output datasets (DISP=NEW, CATLG)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Temporary datasets (&&TEMP)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"GDG generations (GDG(0), GDG(+1))","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Dataset concatenations","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 5: Estimate Complexity","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"scripts/estimate-complexity.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" to calculate migration complexity based on:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Number of job steps","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Conditional logic complexity (COND/IF/THEN/ELSE)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Number of procedures (PROCs)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Data dependency complexity","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Number of programs invoked","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"GDG usage patterns","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 6: Choose Target Platform","type":"text"}]},{"type":"paragraph","content":[{"text":"Select migration target based on requirements:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Spring Batch","type":"text","marks":[{"type":"strong"}]},{"text":": Java-based batch processing with comprehensive features","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apache Airflow","type":"text","marks":[{"type":"strong"}]},{"text":": Python-based workflow orchestration with rich UI","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shell Scripts","type":"text","marks":[{"type":"strong"}]},{"text":": Simple, lightweight for basic sequential processing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Kubernetes Jobs","type":"text","marks":[{"type":"strong"}]},{"text":": Container-based batch processing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"AWS Step Functions","type":"text","marks":[{"type":"strong"}]},{"text":": Serverless workflow orchestration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Azure Logic Apps","type":"text","marks":[{"type":"strong"}]},{"text":": Cloud-based workflow integration","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 7: Generate Migration Strategy","type":"text"}]},{"type":"paragraph","content":[{"text":"Create comprehensive migration report with:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Job Overview","type":"text","marks":[{"type":"strong"}]},{"text":": Purpose, schedule, dependencies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Step Sequence","type":"text","marks":[{"type":"strong"}]},{"text":": Detailed breakdown of each step","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Data Flow Diagram","type":"text","marks":[{"type":"strong"}]},{"text":": Input/output dependencies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Conditional Logic Map","type":"text","marks":[{"type":"strong"}]},{"text":": COND translations (with inversion notes)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Target Implementation","type":"text","marks":[{"type":"strong"}]},{"text":": Workflow definition in chosen platform","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Migration Estimate","type":"text","marks":[{"type":"strong"}]},{"text":": Effort, complexity score, risk assessment","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Action Items","type":"text","marks":[{"type":"strong"}]},{"text":": Prioritized tasks with acceptance criteria","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Use template: ","type":"text"},{"text":"assets/migration-report-template.md","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Reference","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Critical: COND Logic is INVERTED","type":"text"}]},{"type":"paragraph","content":[{"text":"JCL COND (inverted):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"jcl"},"content":[{"text":"//STEP020 EXEC PGM=PROG2,COND=(0,NE)","type":"text"}]},{"type":"paragraph","content":[{"text":"Means: \"Run if previous RC ≠ 0\" → ","type":"text"},{"text":"Run on ERROR!","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"Modern (normal logic):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"if [ $rc -ne 0 ]; then run_prog2; fi","type":"text"}]},{"type":"paragraph","content":[{"text":"JCL IF/THEN (normal logic):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"jcl"},"content":[{"text":"//IF1 IF RC = 0 THEN\n//STEP020 EXEC PGM=PROG2\n//ENDIF","type":"text"}]},{"type":"paragraph","content":[{"text":"Modern:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"if [ $rc -eq 0 ]; then run_prog2; fi","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Code Patterns","type":"text"}]},{"type":"paragraph","content":[{"text":"Simple Sequential:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"jcl"},"content":[{"text":"//STEP010 EXEC PGM=PROG1\n//INPUT DD DSN=INPUT.FILE,DISP=SHR\n//OUTPUT DD DSN=OUTPUT.FILE,DISP=(NEW,CATLG)\n//STEP020 EXEC PGM=PROG2\n//INPUT DD DSN=OUTPUT.FILE,DISP=SHR","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"#!/bin/bash\nset -e\nprog1 --input=\"input.file\" --output=\"output.file\" || exit 8\nprog2 --input=\"output.file\" || exit 8","type":"text"}]},{"type":"paragraph","content":[{"text":"Conditional (COND - inverted!):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"jcl"},"content":[{"text":"//STEP010 EXEC PGM=VALIDATE\n//STEP020 EXEC PGM=PROCESS,COND=(0,NE)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"validate_data\nrc=$?\nif [ $rc -ne 0 ]; then process_data; fi # INVERTED!","type":"text"}]},{"type":"paragraph","content":[{"text":"IF/THEN/ELSE (normal logic):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"jcl"},"content":[{"text":"//STEP010 EXEC PGM=VALIDATE\n//IF1 IF RC = 0 THEN\n//STEP020 EXEC PGM=PROCESSOK\n//ELSE\n//STEP030 EXEC PGM=PROCESSERR\n//ENDIF","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"validate_data\nrc=$?\nif [ $rc -eq 0 ]; then processok; else processerr; fi","type":"text"}]},{"type":"paragraph","content":[{"text":"Procedure:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"jcl"},"content":[{"text":"//MYPROC PROC MEMBER=,INFILE=\n//STEP1 EXEC PGM=PROG1\n//SYSIN DD DSN=&MEMBER,DISP=SHR\n// PEND","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"function myproc() {\n prog1 --sysin=\"$1\" --input=\"$2\"\n}\nmyproc \"test.data\" \"prod.file\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Target Platforms","type":"text"}]},{"type":"paragraph","content":[{"text":"Spring Batch:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"java"},"content":[{"text":"@Bean\npublic Job job() {\n return jobBuilderFactory.get(\"job\")\n .start(step1()).next(step2())\n .on(\"FAILED\").to(errorStep())\n .from(step2()).on(\"*\").to(step3())\n .end().build();\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Airflow DAG:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"with DAG('job', schedule_interval='@daily') as dag:\n step1 = BashOperator(task_id='step1', bash_command='prog1.sh')\n step2 = BashOperator(task_id='step2', bash_command='prog2.sh')\n step1 >> step2","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Key Patterns","type":"text"}]},{"type":"paragraph","content":[{"text":"Error Handling:","type":"text","marks":[{"type":"strong"}]},{"text":" COND-based → ","type":"text"},{"text":"if [ $rc -ne 0 ]; then error_handler; fi","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"GDG:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"GDG(0)","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"get_latest_generation","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"GDG(+1)","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"create_new_generation","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"Concatenation:","type":"text","marks":[{"type":"strong"}]},{"text":" Multiple DD → ","type":"text"},{"text":"cat file1 file2 file3 | process","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"Restart:","type":"text","marks":[{"type":"strong"}]},{"text":" COND restart → checkpoint files (","type":"text"},{"text":"touch .checkpoint_step","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Return Code Reference","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"RC","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Meaning","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Action","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Success","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Continue","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Warning","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Continue (informational)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Error","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"May continue based on COND","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"12","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Severe Error","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Typically stop","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"16","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fatal Error","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Abort job","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Migration Checklist","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Extract job structure, list steps in order, identify programs/procedures, document COND/IF logic","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Map input/output datasets, identify temp datasets, document GDG usage, track data dependencies","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Convert COND to normal logic (","type":"text"},{"text":"INVERT!","type":"text","marks":[{"type":"strong"}]},{"text":"), translate IF/THEN/ELSE, handle error paths","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Choose target (Spring Batch/Airflow/shell), define job structure, implement steps, add monitoring","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Test normal path, error conditions, conditional branches with production-like data","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Document job purpose, schedule, dependencies, special requirements","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Critical Tips","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"COND is INVERTED","type":"text","marks":[{"type":"strong"}]},{"text":" - step runs when condition is FALSE! Draw truth tables if needed.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Return codes","type":"text","marks":[{"type":"strong"}]},{"text":": 0=success, 4=warning (OK), 8+=error","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Data dependencies","type":"text","marks":[{"type":"strong"}]},{"text":": Carefully map to avoid race conditions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Restart capability","type":"text","marks":[{"type":"strong"}]},{"text":": Implement checkpointing if needed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Monitoring","type":"text","marks":[{"type":"strong"}]},{"text":": Add logging and alerting to modern workflows","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Output Structure","type":"text"}]},{"type":"paragraph","content":[{"text":"Provide: Job overview, step sequence, data flow, conditional logic, migration target, workflow definition, migration estimate, action items.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Advanced Topics","type":"text"}]},{"type":"paragraph","content":[{"text":"For detailed conversion rules and patterns, see:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pseudocode-jcl-rules.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/pseudocode-jcl-rules.md","title":null}},{"type":"strong"}]},{"text":" - Comprehensive JCL to pseudocode conversion rules including element mapping, return codes, DISP parameters, translation patterns, and COND logic handling","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pseudocode-common-rules.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/pseudocode-common-rules.md","title":null}},{"type":"strong"}]},{"text":" - Common pseudocode syntax and conventions applicable to all languages","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"testing-strategy.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/testing-strategy.md","title":null}},{"type":"strong"}]},{"text":" - Comprehensive testing approach including unit tests, integration tests, parallel validation, and data-driven testing for migrated workflows","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"transaction-handling.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/transaction-handling.md","title":null}},{"type":"strong"}]},{"text":" - Transaction management, rollback strategies, and ACID compliance for batch jobs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"messaging-integration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/messaging-integration.md","title":null}},{"type":"strong"}]},{"text":" - Message queue integration patterns (MQ, JMS, Kafka) for event-driven workflows","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"performance-patterns.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/performance-patterns.md","title":null}},{"type":"strong"}]},{"text":" - Batch processing optimization, memory management, parallel processing, and performance tuning","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Tools and Scripts","type":"text"}]},{"type":"paragraph","content":[{"text":"All scripts support cross-platform execution (Windows PowerShell, bash):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"analyze-dependencies.sh/ps1","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Generate dependency graph in JSON format showing job-to-job, job-to-dataset, and procedure dependencies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"extract-structure.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Parse JCL files and extract structure (job cards, steps, DD statements, COND logic) to JSON","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"generate-java-classes.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Generate Java POJOs from data structures for Spring Batch item readers/writers","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"estimate-complexity.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" - Calculate migration complexity score based on steps, conditional logic, procedures, and data dependencies","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Scripts use standard libraries only and output JSON for easy integration with CI/CD pipelines and migration tracking tools.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Integration","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Works with job schedulers (Control-M, cron), workflow platforms (Spring Batch, Airflow, K8s), monitoring tools, version control, and CI/CD pipelines.","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"jcl-migration-analyzer","author":"@skillopedia","source":{"stars":12,"repo_name":"hanoi-rainbow","origin_url":"https://github.com/dauquangthanh/hanoi-rainbow/blob/HEAD/skills/jcl-migration-analyzer/SKILL.md","repo_owner":"dauquangthanh","body_sha256":"5ee41250fdb27bbad84b2578ecc45a5a7d109da922b3987fdc7f92c645470c49","cluster_key":"1331ca57919e8fad011e75c12e961084906ec5b87f8a750240a414073acf7a69","clean_bundle":{"format":"clean-skill-bundle-v1","source":"dauquangthanh/hanoi-rainbow/skills/jcl-migration-analyzer/SKILL.md","attachments":[{"id":"036161ee-9ca5-5507-b5c3-caf1dda95af7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/036161ee-9ca5-5507-b5c3-caf1dda95af7/attachment.java","path":"assets/java-class-template.java","size":2351,"sha256":"a5f3c22e411226e03481f5b27c119aefdbd28c2d1a435a31913d6fdce409bc1a","contentType":"text/x-java"},{"id":"4a51f2d6-786e-57ca-8920-be8833713a74","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4a51f2d6-786e-57ca-8920-be8833713a74/attachment.md","path":"assets/migration-report-template.md","size":5133,"sha256":"df0e723f225a7d0d7b87d699325493d83561346357e783af45dfbf810fa9f772","contentType":"text/markdown; charset=utf-8"},{"id":"6ecf3b0a-0b70-5c16-b4d6-99e849812119","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6ecf3b0a-0b70-5c16-b4d6-99e849812119/attachment.md","path":"references/messaging-integration.md","size":11293,"sha256":"b752b762a4bd41e2980dcc091ea2af9de132133c5cf7d744afc33af652e319a8","contentType":"text/markdown; charset=utf-8"},{"id":"06fe8fb7-eddd-5929-ac13-9d2dd15ada9a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/06fe8fb7-eddd-5929-ac13-9d2dd15ada9a/attachment.md","path":"references/performance-patterns.md","size":5977,"sha256":"4cb164ccf8e5ad12a3c8fd850719341081e1f90791690bc314b4787224c68e19","contentType":"text/markdown; charset=utf-8"},{"id":"a338b81e-5915-5c29-8306-3cc359134ed3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a338b81e-5915-5c29-8306-3cc359134ed3/attachment.md","path":"references/pseudocode-common-rules.md","size":2398,"sha256":"aba4d99d62e72f179b76afee47acc981d8ff7e06f6e172e4a59f0ca19955bb9d","contentType":"text/markdown; charset=utf-8"},{"id":"26f4dc34-a613-528d-99d8-045a33415d2c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/26f4dc34-a613-528d-99d8-045a33415d2c/attachment.md","path":"references/pseudocode-jcl-rules.md","size":3687,"sha256":"959eba0a931179efa3283dbe547a739e452019fe12554ed7c22e556533da9705","contentType":"text/markdown; charset=utf-8"},{"id":"f856545a-d16a-5b58-bd80-87346cccabb3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f856545a-d16a-5b58-bd80-87346cccabb3/attachment.md","path":"references/testing-strategy.md","size":13442,"sha256":"c36a4283182a3d616a3e88ef0e339760e7c2df64bcf2e181e569577b4f769c6b","contentType":"text/markdown; charset=utf-8"},{"id":"b873a03d-c33f-523e-a2f9-9b122298fcca","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b873a03d-c33f-523e-a2f9-9b122298fcca/attachment.md","path":"references/transaction-handling.md","size":11492,"sha256":"ce9c52a6862cfeea9928c239843d9d08a805efbb17a80930278063604d15ad80","contentType":"text/markdown; charset=utf-8"},{"id":"e594b902-cc97-54c9-8ac7-d1b6fa879ca6","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e594b902-cc97-54c9-8ac7-d1b6fa879ca6/attachment.ps1","path":"scripts/analyze-dependencies.ps1","size":5187,"sha256":"caf0faf2bf1fd2ef0d5fd5460bf373ff7ea67e0cf77b31a51285ff20e9423282","contentType":"text/plain; charset=utf-8"},{"id":"feed0fb0-20ee-542b-b561-b06eae926b10","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/feed0fb0-20ee-542b-b561-b06eae926b10/attachment.sh","path":"scripts/analyze-dependencies.sh","size":5201,"sha256":"22d60792d10ea592f4afc9e01a24f885919ca6eb965f7dc3d3e18ed31aa78043","contentType":"application/x-sh; charset=utf-8"},{"id":"9a829453-6bb2-5ab8-8c2b-faafd8c67646","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9a829453-6bb2-5ab8-8c2b-faafd8c67646/attachment.py","path":"scripts/estimate-complexity.py","size":8386,"sha256":"047a5fe4e7134b58d6f5ef1b29a7105d509b1a64ac93ebf06e89a1488505a976","contentType":"text/x-python; charset=utf-8"},{"id":"e2796e68-602c-5dc9-9b4a-8f9a8df98a81","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e2796e68-602c-5dc9-9b4a-8f9a8df98a81/attachment.py","path":"scripts/extract-structure.py","size":7312,"sha256":"6b825c5771778da3c92e375cdbb74d8166c0d69cd5bdf9eaa5e157ccd7646f4f","contentType":"text/x-python; charset=utf-8"},{"id":"76563424-e618-5bf9-bc43-28473b1ba9b5","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/76563424-e618-5bf9-bc43-28473b1ba9b5/attachment.py","path":"scripts/generate-java-classes.py","size":9581,"sha256":"33060a573a7400df5785ceb0d44cb1907f3a295ce9afd9e5843987ae1de92f66","contentType":"text/x-python; charset=utf-8"}],"bundle_sha256":"dd187a1be7766d01197257e55dfc3934815fcbe3cf12829a61f3b69cf94f8e1d","attachment_count":13,"text_attachments":12,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":1,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/jcl-migration-analyzer/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"data-analytics","category_label":"Data"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"data-analytics","metadata":{"version":"1.0","category":"legacy-migration"},"import_tag":"clean-skills-v1","description":"Analyzes legacy JCL (Job Control Language) scripts to assist with migration to modern workflow orchestration and batch processing systems. Extracts job flows, step sequences, data dependencies, conditional logic, and program invocations. Generates migration reports and creates implementation strategies for Spring Batch, Apache Airflow, or shell scripts. Use when working with mainframe job migration, JCL analysis, batch workflow modernization, or when users mention JCL conversion, analyzing .jcl/.JCL files, working with job steps, procedures, or planning workflow orchestration from JCL jobs."}},"renderedAt":1782987404571}

JCL Migration Analyzer Analyzes legacy JCL scripts for migration to modern batch processing and workflow orchestration systems like Spring Batch, Apache Airflow, Kubernetes Jobs, or shell scripts. Overview This skill provides comprehensive analysis and migration planning for JCL (Job Control Language) batch processing systems. It extracts job structures, converts JCL constructs to modern workflow patterns, maps data dependencies, and generates implementation-ready migration strategies. Key Migration Focus : JCL to modern orchestration with proper handling of COND logic inversion, data depende…